Lint: Rewrite Lint diagnostics using Uast.
This commit is contained in:
Generated
+10
@@ -60,6 +60,16 @@
|
|||||||
<element id="archive" name="kotlin-android-extensions-compiler-plugin.jar">
|
<element id="archive" name="kotlin-android-extensions-compiler-plugin.jar">
|
||||||
<element id="module-output" name="android-extensions-compiler" />
|
<element id="module-output" name="android-extensions-compiler" />
|
||||||
</element>
|
</element>
|
||||||
|
<element id="archive" name="android-lint.jar">
|
||||||
|
<element id="module-output" name="uast-kotlin" />
|
||||||
|
<element id="module-output" name="lint-idea" />
|
||||||
|
<element id="module-output" name="uast-java" />
|
||||||
|
<element id="module-output" name="uast-common" />
|
||||||
|
<element id="module-output" name="lint-checks" />
|
||||||
|
<element id="library" level="project" name="guava" />
|
||||||
|
<element id="module-output" name="lint-api" />
|
||||||
|
<element id="module-output" name="uast-android" />
|
||||||
|
</element>
|
||||||
</element>
|
</element>
|
||||||
<element id="directory" name="kotlinc">
|
<element id="directory" name="kotlinc">
|
||||||
<element id="dir-copy" path="$PROJECT_DIR$/dist/kotlinc" />
|
<element id="dir-copy" path="$PROJECT_DIR$/dist/kotlinc" />
|
||||||
|
|||||||
Generated
+8
@@ -3,6 +3,7 @@
|
|||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/Kotlin.iml" filepath="$PROJECT_DIR$/Kotlin.iml" />
|
<module fileurl="file://$PROJECT_DIR$/Kotlin.iml" filepath="$PROJECT_DIR$/Kotlin.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/lint/android-annotations/android-annotations.iml" filepath="$PROJECT_DIR$/plugins/lint/android-annotations/android-annotations.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml" group="plugins/android-extensions" />
|
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml" group="plugins/android-extensions" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml" group="plugins/android-extensions" />
|
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml" group="plugins/android-extensions" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-jps/android-extensions-jps.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-jps/android-extensions-jps.iml" group="plugins/android-extensions" />
|
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-jps/android-extensions-jps.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-jps/android-extensions-jps.iml" group="plugins/android-extensions" />
|
||||||
@@ -59,6 +60,9 @@
|
|||||||
<module fileurl="file://$PROJECT_DIR$/js/js.translator/js.translator.iml" filepath="$PROJECT_DIR$/js/js.translator/js.translator.iml" group="compiler/js" />
|
<module fileurl="file://$PROJECT_DIR$/js/js.translator/js.translator.iml" filepath="$PROJECT_DIR$/js/js.translator/js.translator.iml" group="compiler/js" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" filepath="$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" group="ide/jps" />
|
<module fileurl="file://$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" filepath="$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" group="ide/jps" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compiler/light-classes/light-classes.iml" filepath="$PROJECT_DIR$/compiler/light-classes/light-classes.iml" group="compiler/java" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/light-classes/light-classes.iml" filepath="$PROJECT_DIR$/compiler/light-classes/light-classes.iml" group="compiler/java" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/lint/lint-api/lint-api.iml" filepath="$PROJECT_DIR$/plugins/lint/lint-api/lint-api.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/lint/lint-checks/lint-checks.iml" filepath="$PROJECT_DIR$/plugins/lint/lint-checks/lint-checks.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/lint/lint-idea/lint-idea.iml" filepath="$PROJECT_DIR$/plugins/lint/lint-idea/lint-idea.iml" group="plugins" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compiler/plugin-api/plugin-api.iml" filepath="$PROJECT_DIR$/compiler/plugin-api/plugin-api.iml" group="compiler" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/plugin-api/plugin-api.iml" filepath="$PROJECT_DIR$/compiler/plugin-api/plugin-api.iml" group="compiler" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/plugins/plugins-tests/plugins-tests.iml" filepath="$PROJECT_DIR$/plugins/plugins-tests/plugins-tests.iml" group="plugins" />
|
<module fileurl="file://$PROJECT_DIR$/plugins/plugins-tests/plugins-tests.iml" filepath="$PROJECT_DIR$/plugins/plugins-tests/plugins-tests.iml" group="plugins" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compiler/preloader/preloader.iml" filepath="$PROJECT_DIR$/compiler/preloader/preloader.iml" group="compiler/cli" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/preloader/preloader.iml" filepath="$PROJECT_DIR$/compiler/preloader/preloader.iml" group="compiler/cli" />
|
||||||
@@ -66,6 +70,10 @@
|
|||||||
<module fileurl="file://$PROJECT_DIR$/compiler/resolution/resolution.iml" filepath="$PROJECT_DIR$/compiler/resolution/resolution.iml" group="compiler" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/resolution/resolution.iml" filepath="$PROJECT_DIR$/compiler/resolution/resolution.iml" group="compiler" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" filepath="$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" group="core" />
|
<module fileurl="file://$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" filepath="$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" group="core" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compiler/serialization/serialization.iml" filepath="$PROJECT_DIR$/compiler/serialization/serialization.iml" group="compiler" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/serialization/serialization.iml" filepath="$PROJECT_DIR$/compiler/serialization/serialization.iml" group="compiler" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/lint/uast-android/uast-android.iml" filepath="$PROJECT_DIR$/plugins/lint/uast-android/uast-android.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/uast-common/uast-common.iml" filepath="$PROJECT_DIR$/plugins/uast-common/uast-common.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/uast-java/uast-java.iml" filepath="$PROJECT_DIR$/plugins/uast-java/uast-java.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/plugins/uast-kotlin/uast-kotlin.iml" filepath="$PROJECT_DIR$/plugins/uast-kotlin/uast-kotlin.iml" group="plugins" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compiler/util/util.iml" filepath="$PROJECT_DIR$/compiler/util/util.iml" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/util/util.iml" filepath="$PROJECT_DIR$/compiler/util/util.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/core/util.runtime/util.runtime.iml" filepath="$PROJECT_DIR$/core/util.runtime/util.runtime.iml" group="core" />
|
<module fileurl="file://$PROJECT_DIR$/core/util.runtime/util.runtime.iml" filepath="$PROJECT_DIR$/core/util.runtime/util.runtime.iml" group="core" />
|
||||||
</modules>
|
</modules>
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ Issues fixed:
|
|||||||
- [KT-11487](https://youtrack.jetbrains.com/issue/KT-11487) Fixed sequential build with kapt and stubs enabled when Kotlin source file was modified and no Java source files were modified
|
- [KT-11487](https://youtrack.jetbrains.com/issue/KT-11487) Fixed sequential build with kapt and stubs enabled when Kotlin source file was modified and no Java source files were modified
|
||||||
- [KT-11264](https://youtrack.jetbrains.com/issue/KT-11264) Action to create new activity in Kotlin
|
- [KT-11264](https://youtrack.jetbrains.com/issue/KT-11264) Action to create new activity in Kotlin
|
||||||
- [KT-11201](https://youtrack.jetbrains.com/issue/KT-11201) Do not ignore items with similar names in kapt
|
- [KT-11201](https://youtrack.jetbrains.com/issue/KT-11201) Do not ignore items with similar names in kapt
|
||||||
|
- [KT-7729](https://youtrack.jetbrains.com/issue/KT-7729) Add Android Lint checks for Kotlin (Android Studio 1.5)
|
||||||
|
|
||||||
### Maven
|
### Maven
|
||||||
|
|
||||||
|
|||||||
@@ -253,3 +253,6 @@ debugger.field.watchpoints.tab.title=Kotlin Field Watchpoints
|
|||||||
debugger.field.watchpoints.properties.panel.field.access.label=Field &access
|
debugger.field.watchpoints.properties.panel.field.access.label=Field &access
|
||||||
debugger.field.watchpoints.properties.panel.field.modification.label=Field &modification
|
debugger.field.watchpoints.properties.panel.field.modification.label=Field &modification
|
||||||
debugger.field.watchpoints.properties.panel.field.initialization.label=Field &initialization
|
debugger.field.watchpoints.properties.panel.field.initialization.label=Field &initialization
|
||||||
|
|
||||||
|
# Android Lint
|
||||||
|
android.klint.inspections.group.name=Android Lint for Kotlin
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
<idea-plugin>
|
||||||
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
<externalAnnotator language="kotlin" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintExternalAnnotator"/>
|
||||||
|
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAaptCrash" displayName="Potential AAPT crash" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAaptCrashInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAccidentalOctal" displayName="Accidental Octal" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAccidentalOctalInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAdapterViewChildren" displayName="AdapterViews cannot have children in XML" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAdapterViewChildrenInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAddJavascriptInterface" displayName="addJavascriptInterface Called" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAddJavascriptInterfaceInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAllowBackup" displayName="Missing allowBackup attribute" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAllowBackupInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAlwaysShowAction" displayName="Usage of showAsAction=always" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAlwaysShowActionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAppCompatMethod" displayName="Using Wrong AppCompat Method" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAppCompatMethodInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAppCompatResource" displayName="Menu namespace" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAppCompatResourceInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAppIndexingApiError" displayName="Wrong usage of AppIndexing api" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAppIndexingApiErrorInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAppIndexingApiWarning" displayName="Missing AppIndexing Support" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAppIndexingApiWarningInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintAssert" displayName="Assertions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintAssertInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintBackButton" displayName="Back button" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintBackButtonInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintButtonCase" displayName="Cancel/OK dialog button capitalization" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintButtonCaseInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintButtonOrder" displayName="Button order" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintButtonOrderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintButtonStyle" displayName="Button should be borderless" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintButtonStyleInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintByteOrderMark" displayName="Byte order mark inside files" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintByteOrderMarkInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintCommitPrefEdits" displayName="Missing commit() on SharedPreference editor" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintCommitPrefEditsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintCommitTransaction" displayName="Missing commit() calls" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintCommitTransactionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintContentDescription" displayName="Image without contentDescription" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintContentDescriptionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintCustomViewStyleable" displayName="Mismatched Styleable/Custom View Name" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintCustomViewStyleableInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintCutPasteId" displayName="Likely cut & paste mistakes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintCutPasteIdInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDeprecated" displayName="Using deprecated resources" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDeprecatedInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDeviceAdmin" displayName="Malformed Device Admin" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDeviceAdminInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDisableBaselineAlignment" displayName="Missing baselineAligned attribute" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDisableBaselineAlignmentInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDrawAllocation" displayName="Memory allocations within drawing code" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDrawAllocationInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDuplicateActivity" displayName="Activity registered more than once" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDuplicateActivityInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDuplicateDefinition" displayName="Duplicate definitions of resources" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDuplicateDefinitionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDuplicateIds" displayName="Duplicate ids within a single layout" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDuplicateIdsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDuplicateIncludedIds" displayName="Duplicate ids across layouts combined with include tags" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDuplicateIncludedIdsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintDuplicateUsesFeature" displayName="Feature declared more than once" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintDuplicateUsesFeatureInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintEasterEgg" displayName="Code contains easter egg" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintEasterEggInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintEnforceUTF8" displayName="Encoding used in resource files is not UTF-8" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintEnforceUTF8Inspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintExportedContentProvider" displayName="Content provider does not require permission" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintExportedContentProviderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintExportedPreferenceActivity" displayName="PreferenceActivity should not be exported" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintExportedPreferenceActivityInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintExportedReceiver" displayName="Receiver does not require permission" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintExportedReceiverInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintExportedService" displayName="Exported service does not require permission" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintExportedServiceInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintExtraText" displayName="Extraneous text in resource files" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintExtraTextInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintExtraTranslation" displayName="Extra translation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintExtraTranslationInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintFullBackupContent" displayName="Valid Full Backup Content File" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintFullBackupContentInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGetInstance" displayName="Cipher.getInstance with ECB" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGetInstanceInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGifUsage" displayName="Using .gif format for bitmaps is discouraged" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGifUsageInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleCompatible" displayName="Incompatible Gradle Versions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleCompatibleInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleCompatiblePlugin" displayName="Incompatible Android Gradle Plugin Version" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleCompatiblePluginInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleDependency" displayName="Obsolete Gradle Dependency" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleDependencyInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleDeprecated" displayName="Deprecated Gradle Construct" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleDeprecatedInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleDynamicVersion" displayName="Gradle Dynamic Version" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleDynamicVersionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleGetter" displayName="Gradle Implicit Getter Call" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleGetterInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleIdeError" displayName="Gradle IDE Support Issues" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleIdeErrorInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradleOverrides" displayName="Value overridden by Gradle build script" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradleOverridesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGradlePath" displayName="Gradle Path Issues" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGradlePathInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGrantAllUris" displayName="Content provider shares everything" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGrantAllUrisInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintGridLayout" displayName="GridLayout validation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintGridLayoutInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintHandlerLeak" displayName="Handler reference leaks" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintHandlerLeakInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintHardcodedDebugMode" displayName="Hardcoded value of android:debuggable in the manifest" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintHardcodedDebugModeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintHardcodedText" displayName="Hardcoded text" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintHardcodedTextInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconColors" displayName="Icon colors do not follow the recommended visual style" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconColorsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconDensities" displayName="Icon densities validation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconDensitiesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconDipSize" displayName="Icon density-independent size validation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconDipSizeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconDuplicates" displayName="Duplicated icons under different names" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconDuplicatesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconDuplicatesConfig" displayName="Identical bitmaps across various configurations" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconDuplicatesConfigInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconExpectedSize" displayName="Icon has incorrect size" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconExpectedSizeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconExtension" displayName="Icon format does not match the file extension" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconExtensionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconLauncherShape" displayName="The launcher icon shape should use a distinct silhouette" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconLauncherShapeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconLocation" displayName="Image defined in density-independent drawable folder" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconLocationInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconMissingDensityFolder" displayName="Missing density folder" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconMissingDensityFolderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconMixedNinePatch" displayName="Clashing PNG and 9-PNG files" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconMixedNinePatchInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconNoDpi" displayName="Icon appears in both -nodpi and dpi folders" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconNoDpiInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIconXmlAndPng" displayName="Icon is specified both as .xml file and as a bitmap" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIconXmlAndPngInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIllegalResourceRef" displayName="Name and version must be integer or string, not resource" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIllegalResourceRefInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintImpliedQuantity" displayName="Implied Quantities" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintImpliedQuantityInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInOrMmUsage" displayName="Using mm or in dimensions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInOrMmUsageInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintIncludeLayoutParam" displayName="Ignored layout params on include" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintIncludeLayoutParamInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInconsistentArrays" displayName="Inconsistencies in array element counts" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInconsistentArraysInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInconsistentLayout" displayName="Inconsistent Layouts" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInconsistentLayoutInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInefficientWeight" displayName="Inefficient layout weight" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInefficientWeightInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInflateParams" displayName="Layout Inflation without a Parent" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInflateParamsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInlinedApi" displayName="Using inlined constants on older versions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInlinedApiInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInnerclassSeparator" displayName="Inner classes should use $ rather than ." groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInnerclassSeparatorInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInvalidId" displayName="Invalid ID declaration" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInvalidIdInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintInvalidResourceFolder" displayName="Invalid Resource Folder" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintInvalidResourceFolderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintJavascriptInterface" displayName="Missing @JavascriptInterface on methods" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintJavascriptInterfaceInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintLabelFor" displayName="Missing labelFor attribute" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintLabelForInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintLibraryCustomView" displayName="Custom views in libraries should use res-auto-namespace" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintLibraryCustomViewInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintLocalSuppress" displayName="@SuppressLint on invalid element" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintLocalSuppressInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintLocaleFolder" displayName="Wrong locale name" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintLocaleFolderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintLogConditional" displayName="Unconditional Logging Calls" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintLogConditionalInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintLogTagMismatch" displayName="Mismatched Log Tags" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintLogTagMismatchInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintLongLogTag" displayName="Too Long Log Tags" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintLongLogTagInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMangledCRLF" displayName="Mangled file line endings" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMangledCRLFInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintManifestOrder" displayName="Incorrect order of elements in manifest" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintManifestOrderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMenuTitle" displayName="Missing menu title" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMenuTitleInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMergeRootFrame" displayName="FrameLayout can be replaced with <merge> tag" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMergeRootFrameInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMipmapIcons" displayName="Use Mipmap Launcher Icons" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMipmapIconsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMissingApplicationIcon" displayName="Missing application icon" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMissingApplicationIconInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMissingId" displayName="Fragments should specify an id or tag" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMissingIdInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMissingPrefix" displayName="Missing Android XML namespace" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMissingPrefixInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMissingQuantity" displayName="Missing quantity translation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMissingQuantityInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMissingSuperCall" displayName="Missing Super Call" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMissingSuperCallInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMissingTranslation" displayName="Incomplete translation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMissingTranslationInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMissingVersion" displayName="Missing application name/version" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMissingVersionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMockLocation" displayName="Using mock location provider in production" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMockLocationInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintMultipleUsesSdk" displayName="Multiple <uses-sdk> elements in the manifest" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintMultipleUsesSdkInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintNegativeMargin" displayName="Negative Margins" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintNegativeMarginInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintNestedScrolling" displayName="Nested scrolling widgets" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintNestedScrollingInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintNestedWeights" displayName="Nested layout weights" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintNestedWeightsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintNewApi" displayName="Calling new methods on older versions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintNewApiInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintNewerVersionAvailable" displayName="Newer Library Versions Available" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintNewerVersionAvailableInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintNfcTechWhitespace" displayName="Whitespace in NFC tech lists" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintNfcTechWhitespaceInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintNotSibling" displayName="RelativeLayout Invalid Constraints" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintNotSiblingInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintObsoleteLayoutParam" displayName="Obsolete layout params" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintObsoleteLayoutParamInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintOldTargetApi" displayName="Target SDK attribute is not targeting latest version" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintOldTargetApiInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintOrientation" displayName="Missing explicit orientation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintOrientationInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintOverdraw" displayName="Overdraw: Painting regions more than once" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintOverdrawInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintOverride" displayName="Method conflicts with new inherited method" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintOverrideInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintOverrideAbstract" displayName="Not overriding abstract methods on older platforms" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintOverrideAbstractInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintPackagedPrivateKey" displayName="Packaged private key" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintPackagedPrivateKeyInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintPackageManagerGetSignatures" displayName="Potential Multiple Certificate Exploit" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintPackageManagerGetSignaturesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintParcelCreator" displayName="Missing Parcelable CREATOR field" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintParcelCreatorInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintPluralsCandidate" displayName="Potential Plurals" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintPluralsCandidateInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintPrivateResource" displayName="Using private resources" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintPrivateResourceInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintProguard" displayName="Using obsolete ProGuard configuration" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintProguardInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintProguardSplit" displayName="Proguard.cfg file contains generic Android rules" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintProguardSplitInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintPropertyEscape" displayName="Incorrect property escapes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintPropertyEscapeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintProtectedPermissions" displayName="Using system app permission" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintProtectedPermissionsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintPxUsage" displayName="Using 'px' dimension" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintPxUsageInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRecycle" displayName="Missing recycle() calls" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRecycleInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintReferenceType" displayName="Incorrect reference types" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintReferenceTypeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRegistered" displayName="Class is not registered in the manifest" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRegisteredInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRelativeOverlap" displayName="Overlapping items in RelativeLayout" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRelativeOverlapInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRequiredSize" displayName="Missing layout_width or layout_height attributes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRequiredSizeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintResAuto" displayName="Hardcoded Package in Namespace" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintResAutoInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintResourceCycle" displayName="Cycle in resource definitions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintResourceCycleInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintResourceName" displayName="Resource with Wrong Prefix" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintResourceNameInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRtlCompat" displayName="Right-to-left text compatibility issues" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRtlCompatInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRtlEnabled" displayName="Using RTL attributes without enabling RTL support" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRtlEnabledInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRtlHardcoded" displayName="Using left/right instead of start/end attributes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRtlHardcodedInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintRtlSymmetry" displayName="Padding and margin symmetry" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintRtlSymmetryInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSQLiteString" displayName="Using STRING instead of TEXT" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSQLiteStringInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintScrollViewCount" displayName="ScrollViews can have only one child" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintScrollViewCountInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintScrollViewSize" displayName="ScrollView size validation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintScrollViewSizeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSdCardPath" displayName="Hardcoded reference to /sdcard" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSdCardPathInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSelectableText" displayName="Dynamic text should probably be selectable" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSelectableTextInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintServiceCast" displayName="Wrong system service casts" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintServiceCastInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSetJavaScriptEnabled" displayName="Using setJavaScriptEnabled" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSetJavaScriptEnabledInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintShortAlarm" displayName="Short or Frequent Alarm" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintShortAlarmInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintShowToast" displayName="Toast created but not shown" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintShowToastInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSignatureOrSystemPermissions" displayName="signatureOrSystem permissions declared" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSignatureOrSystemPermissionsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSimpleDateFormat" displayName="Implied locale in date format" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSimpleDateFormatInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSmallSp" displayName="Text size is too small" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSmallSpInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSpUsage" displayName="Using dp instead of sp for text sizes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSpUsageInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintStateListReachable" displayName="Unreachable state in a <selector>" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintStateListReachableInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintStopShip" displayName="Code contains STOPSHIP marker" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintStopShipInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintStringFormatCount" displayName="Formatting argument types incomplete or inconsistent" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintStringFormatCountInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintStringFormatInvalid" displayName="Invalid format string" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintStringFormatInvalidInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintStringFormatMatches" displayName="String.format string doesn't match the XML format string" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintStringFormatMatchesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintStringShouldBeInt" displayName="String should be int" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintStringShouldBeIntInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSuspicious0dp" displayName="Suspicious 0dp dimension" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSuspicious0dpInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintSuspiciousImport" displayName="'import android.R' statement" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintSuspiciousImportInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTextFields" displayName="Missing inputType or hint" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTextFieldsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTextViewEdits" displayName="TextView should probably be an EditText instead" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTextViewEditsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTooDeepLayout" displayName="Layout hierarchy is too deep" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTooDeepLayoutInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTooManyViews" displayName="Layout has too many views" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTooManyViewsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTypographyDashes" displayName="Hyphen can be replaced with dash" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTypographyDashesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTypographyEllipsis" displayName="Ellipsis string can be replaced with ellipsis character" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTypographyEllipsisInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTypographyFractions" displayName="Fraction string can be replaced with fraction character" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTypographyFractionsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTypographyOther" displayName="Other typographical problems" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTypographyOtherInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTypographyQuotes" displayName="Straight quotes can be replaced with curvy quotes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTypographyQuotesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintTypos" displayName="Spelling error" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintTyposInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUniquePermission" displayName="Permission names are not unique" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUniquePermissionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUnknownId" displayName="Reference to an unknown id" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUnknownIdInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUnknownIdInLayout" displayName="Reference to an id that is not in the current layout" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUnknownIdInLayoutInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUnlocalizedSms" displayName="SMS phone number missing country code" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUnlocalizedSmsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUnusedAttribute" displayName="Attribute unused on older versions" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUnusedAttributeInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUnusedIds" displayName="Unused id" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUnusedIdsInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUnusedQuantity" displayName="Unused quantity translations" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUnusedQuantityInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUnusedResources" displayName="Unused resources" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUnusedResourcesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUseAlpha2" displayName="Using 3-letter Codes" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUseAlpha2Inspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUseCompoundDrawables" displayName="Node can be replaced by a TextView with compound drawables" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUseCompoundDrawablesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUseSparseArrays" displayName="HashMap can be replaced with SparseArray" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUseSparseArraysInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUseValueOf" displayName="Should use valueOf instead of new" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUseValueOfInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUselessLeaf" displayName="Useless leaf layout" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUselessLeafInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUselessParent" displayName="Useless parent layout" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUselessParentInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUsesMinSdkAttributes" displayName="Minimum SDK and target SDK attributes not defined" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUsesMinSdkAttributesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintUsingHttp" displayName="Using HTTP instead of HTTPS" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintUsingHttpInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintValidFragment" displayName="Fragment not instantiatable" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintValidFragmentInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintViewConstructor" displayName="Missing View constructors for XML inflation" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintViewConstructorInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintViewHolder" displayName="View Holder Candidates" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintViewHolderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWebViewLayout" displayName="WebViews in wrap_content parents" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWebViewLayoutInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWorldReadableFiles" displayName="openFileOutput() call passing MODE_WORLD_READABLE" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWorldReadableFilesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWorldWriteableFiles" displayName="openFileOutput() call passing MODE_WORLD_WRITEABLE" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWorldWriteableFilesInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWrongCall" displayName="Using wrong draw/layout method" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWrongCallInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWrongCase" displayName="Wrong case for view tag" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWrongCaseInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWrongFolder" displayName="Resource file in the wrong res folder" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWrongFolderInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWrongRegion" displayName="Suspicious Language/Region Combination" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWrongRegionInspection"/>
|
||||||
|
<globalInspection hasStaticDescription="true" shortName="AndroidLintWrongViewCast" displayName="Mismatched view type" groupKey="android.klint.inspections.group.name" bundle="org.jetbrains.kotlin.idea.KotlinBundle" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidLintWrongViewCastInspection"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensionPoints>
|
||||||
|
<extensionPoint qualifiedName="com.android.tools.lint.client.api.lintLanguageExtension"
|
||||||
|
interface="com.android.tools.klint.client.api.LintLanguageExtension"
|
||||||
|
area="IDEA_PROJECT"/>
|
||||||
|
</extensionPoints>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.android.tools.lint.client.api">
|
||||||
|
<lintLanguageExtension implementation="org.jetbrains.android.inspections.klint.KotlinLintLanguageExtension"/>
|
||||||
|
<lintLanguageExtension implementation="com.android.tools.klint.client.api.JavaLintLanguageExtension"/>
|
||||||
|
</extensions>
|
||||||
|
</idea-plugin>
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
<idea-plugin>
|
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<xi:include href="android-lint.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.navigation.KotlinAndroidGotoDeclarationHandler"/>
|
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.navigation.KotlinAndroidGotoDeclarationHandler"/>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes that a parameter, field or method return value can never be null.
|
||||||
|
* <p/>
|
||||||
|
* This is a marker annotation and it has no specific attributes.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({METHOD,PARAMETER,LOCAL_VARIABLE,FIELD})
|
||||||
|
public @interface NonNull {
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.PACKAGE;
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes that all parameters, fields or methods within a class or method by
|
||||||
|
* default can not be null. This can be overridden by adding specific
|
||||||
|
* {@link com.android.annotations.Nullable} annotations on fields, parameters or
|
||||||
|
* methods that should not use the default.
|
||||||
|
* <p/>
|
||||||
|
* NOTE: Eclipse does not yet handle defaults well (in particular, if
|
||||||
|
* you add this on a class which implements Comparable, then it will insist
|
||||||
|
* that your compare method is changing the nullness of the compare parameter,
|
||||||
|
* so you'll need to add @Nullable on it, which also is not right (since
|
||||||
|
* the method should have implied @NonNull and you do not need to check
|
||||||
|
* the parameter.). For now, it's best to individually annotate methods,
|
||||||
|
* parameters and fields.
|
||||||
|
* <p/>
|
||||||
|
* This is a marker annotation and it has no specific attributes.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({PACKAGE, TYPE})
|
||||||
|
public @interface NonNullByDefault {
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes that a parameter, field or method return value can be null.
|
||||||
|
* <b>Note</b>: this is the default assumption for most Java APIs and the
|
||||||
|
* default assumption made by most static code checking tools, so usually you
|
||||||
|
* don't need to use this annotation; its primary use is to override a default
|
||||||
|
* wider annotation like {@link NonNullByDefault}.
|
||||||
|
* <p/>
|
||||||
|
* When decorating a method call parameter, this denotes the parameter can
|
||||||
|
* legitimately be null and the method will gracefully deal with it. Typically
|
||||||
|
* used on optional parameters.
|
||||||
|
* <p/>
|
||||||
|
* When decorating a method, this denotes the method might legitimately return
|
||||||
|
* null.
|
||||||
|
* <p/>
|
||||||
|
* This is a marker annotation and it has no specific attributes.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({METHOD, PARAMETER, LOCAL_VARIABLE, FIELD})
|
||||||
|
public @interface Nullable {
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes that the class, method or field has its visibility relaxed so
|
||||||
|
* that unit tests can access it.
|
||||||
|
* <p/>
|
||||||
|
* The <code>visibility</code> argument can be used to specific what the original
|
||||||
|
* visibility should have been if it had not been made public or package-private for testing.
|
||||||
|
* The default is to consider the element private.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface VisibleForTesting {
|
||||||
|
/**
|
||||||
|
* Intended visibility if the element had not been made public or package-private for
|
||||||
|
* testing.
|
||||||
|
*/
|
||||||
|
enum Visibility {
|
||||||
|
/** The element should be considered protected. */
|
||||||
|
PROTECTED,
|
||||||
|
/** The element should be considered package-private. */
|
||||||
|
PACKAGE,
|
||||||
|
/** The element should be considered private. */
|
||||||
|
PRIVATE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intended visibility if the element had not been made public or package-private for testing.
|
||||||
|
* If not specified, one should assume the element originally intended to be private.
|
||||||
|
*/
|
||||||
|
Visibility visibility() default Visibility.PRIVATE;
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.annotations.concurrency;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the target field or method should only be accessed
|
||||||
|
* with the specified lock being held.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||||
|
public @interface GuardedBy {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.annotations.concurrency;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the target class to which this annotation is applied
|
||||||
|
* is immutable.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public @interface Immutable {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="guava" level="project" />
|
||||||
|
<orderEntry type="module" module-name="uast-common" />
|
||||||
|
<orderEntry type="module" module-name="uast-java" />
|
||||||
|
<orderEntry type="module" module-name="uast-android" />
|
||||||
|
<orderEntry type="library" name="android-plugin" level="project" />
|
||||||
|
<orderEntry type="library" name="intellij-core" level="project" />
|
||||||
|
<orderEntry type="module" module-name="android-annotations" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -14,25 +14,16 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.ClassContext;
|
import com.android.tools.klint.detector.api.ClassContext;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Detector.ClassScanner;
|
import com.android.tools.klint.detector.api.Detector.ClassScanner;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
import org.objectweb.asm.tree.*;
|
||||||
|
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import java.util.*;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
import org.objectweb.asm.tree.InsnList;
|
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialized visitor for running detectors on a class object model.
|
* Specialized visitor for running detectors on a class object model.
|
||||||
@@ -90,9 +81,9 @@ class AsmVisitor {
|
|||||||
if (names != null) {
|
if (names != null) {
|
||||||
checkFullClass = false;
|
checkFullClass = false;
|
||||||
for (String element : names) {
|
for (String element : names) {
|
||||||
List<Detector.ClassScanner> list = mMethodNameToChecks.get(element);
|
List<ClassScanner> list = mMethodNameToChecks.get(element);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new ArrayList<Detector.ClassScanner>();
|
list = new ArrayList<ClassScanner>();
|
||||||
mMethodNameToChecks.put(element, list);
|
mMethodNameToChecks.put(element, list);
|
||||||
}
|
}
|
||||||
list.add(scanner);
|
list.add(scanner);
|
||||||
@@ -103,9 +94,9 @@ class AsmVisitor {
|
|||||||
if (owners != null) {
|
if (owners != null) {
|
||||||
checkFullClass = false;
|
checkFullClass = false;
|
||||||
for (String element : owners) {
|
for (String element : owners) {
|
||||||
List<Detector.ClassScanner> list = mMethodOwnerToChecks.get(element);
|
List<ClassScanner> list = mMethodOwnerToChecks.get(element);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new ArrayList<Detector.ClassScanner>();
|
list = new ArrayList<ClassScanner>();
|
||||||
mMethodOwnerToChecks.put(element, list);
|
mMethodOwnerToChecks.put(element, list);
|
||||||
}
|
}
|
||||||
list.add(scanner);
|
list.add(scanner);
|
||||||
|
|||||||
+3
-3
@@ -14,12 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,11 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.DOT_CLASS;
|
|
||||||
import static com.android.SdkConstants.DOT_JAR;
|
|
||||||
import static org.objectweb.asm.Opcodes.ASM5;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
@@ -26,7 +22,6 @@ import com.android.annotations.VisibleForTesting;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.io.Closeables;
|
import com.google.common.io.Closeables;
|
||||||
|
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
|
||||||
@@ -40,6 +35,10 @@ import java.util.Map;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.DOT_CLASS;
|
||||||
|
import static com.android.SdkConstants.DOT_JAR;
|
||||||
|
import static org.objectweb.asm.Opcodes.ASM5;
|
||||||
|
|
||||||
/** A class, present either as a .class file on disk, or inside a .jar file. */
|
/** A class, present either as a .class file on disk, or inside a .jar file. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
class ClassEntry implements Comparable<ClassEntry> {
|
class ClassEntry implements Comparable<ClassEntry> {
|
||||||
|
|||||||
+2
-2
@@ -13,10 +13,10 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@@ -14,14 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+13
-29
@@ -14,48 +14,32 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CURRENT_PLATFORM;
|
|
||||||
import static com.android.SdkConstants.PLATFORM_WINDOWS;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.TextFormat;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
import com.android.utils.XmlUtils;
|
import com.android.utils.XmlUtils;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
import org.w3c.dom.*;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.NamedNodeMap;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.SAXParseException;
|
import org.xml.sax.SAXParseException;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.*;
|
||||||
import java.io.File;
|
import java.util.*;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.regex.PatternSyntaxException;
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.CURRENT_PLATFORM;
|
||||||
|
import static com.android.SdkConstants.PLATFORM_WINDOWS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of a {@link Configuration} which reads and writes
|
* Default implementation of a {@link Configuration} which reads and writes
|
||||||
* configuration data into {@code lint.xml} in the project directory.
|
* configuration data into {@code lint.xml} in the project directory.
|
||||||
|
|||||||
@@ -14,53 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
|
|
||||||
import static com.android.SdkConstants.ABS_LIST_VIEW;
|
|
||||||
import static com.android.SdkConstants.ABS_SEEK_BAR;
|
|
||||||
import static com.android.SdkConstants.ABS_SPINNER;
|
|
||||||
import static com.android.SdkConstants.ADAPTER_VIEW;
|
|
||||||
import static com.android.SdkConstants.AUTO_COMPLETE_TEXT_VIEW;
|
|
||||||
import static com.android.SdkConstants.BUTTON;
|
|
||||||
import static com.android.SdkConstants.CHECKABLE;
|
|
||||||
import static com.android.SdkConstants.CHECKED_TEXT_VIEW;
|
|
||||||
import static com.android.SdkConstants.CHECK_BOX;
|
|
||||||
import static com.android.SdkConstants.COMPOUND_BUTTON;
|
|
||||||
import static com.android.SdkConstants.EDIT_TEXT;
|
|
||||||
import static com.android.SdkConstants.EXPANDABLE_LIST_VIEW;
|
|
||||||
import static com.android.SdkConstants.FRAME_LAYOUT;
|
|
||||||
import static com.android.SdkConstants.GALLERY;
|
|
||||||
import static com.android.SdkConstants.GRID_VIEW;
|
|
||||||
import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
|
|
||||||
import static com.android.SdkConstants.IMAGE_BUTTON;
|
|
||||||
import static com.android.SdkConstants.IMAGE_VIEW;
|
|
||||||
import static com.android.SdkConstants.LINEAR_LAYOUT;
|
|
||||||
import static com.android.SdkConstants.LIST_VIEW;
|
|
||||||
import static com.android.SdkConstants.MULTI_AUTO_COMPLETE_TEXT_VIEW;
|
|
||||||
import static com.android.SdkConstants.PROGRESS_BAR;
|
|
||||||
import static com.android.SdkConstants.RADIO_BUTTON;
|
|
||||||
import static com.android.SdkConstants.RADIO_GROUP;
|
|
||||||
import static com.android.SdkConstants.RELATIVE_LAYOUT;
|
|
||||||
import static com.android.SdkConstants.SCROLL_VIEW;
|
|
||||||
import static com.android.SdkConstants.SEEK_BAR;
|
|
||||||
import static com.android.SdkConstants.SPINNER;
|
|
||||||
import static com.android.SdkConstants.SURFACE_VIEW;
|
|
||||||
import static com.android.SdkConstants.SWITCH;
|
|
||||||
import static com.android.SdkConstants.TABLE_LAYOUT;
|
|
||||||
import static com.android.SdkConstants.TABLE_ROW;
|
|
||||||
import static com.android.SdkConstants.TAB_HOST;
|
|
||||||
import static com.android.SdkConstants.TAB_WIDGET;
|
|
||||||
import static com.android.SdkConstants.TEXT_VIEW;
|
|
||||||
import static com.android.SdkConstants.TOGGLE_BUTTON;
|
|
||||||
import static com.android.SdkConstants.VIEW;
|
|
||||||
import static com.android.SdkConstants.VIEW_ANIMATOR;
|
|
||||||
import static com.android.SdkConstants.VIEW_GROUP;
|
|
||||||
import static com.android.SdkConstants.VIEW_PKG_PREFIX;
|
|
||||||
import static com.android.SdkConstants.VIEW_STUB;
|
|
||||||
import static com.android.SdkConstants.VIEW_SWITCHER;
|
|
||||||
import static com.android.SdkConstants.WEB_VIEW;
|
|
||||||
import static com.android.SdkConstants.WIDGET_PKG_PREFIX;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
@@ -72,6 +26,8 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default simple implementation of an {@link SdkInfo}
|
* Default simple implementation of an {@link SdkInfo}
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -14,28 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.annotations.VisibleForTesting;
|
import com.android.annotations.VisibleForTesting;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry which provides a list of checks to be performed on an Android project
|
* Registry which provides a list of checks to be performed on an Android project
|
||||||
|
|||||||
+3
-3
@@ -13,11 +13,11 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.utils.SdkUtils;
|
import com.android.utils.SdkUtils;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.klint.client.api;
|
||||||
|
|
||||||
|
import org.jetbrains.uast.UastConverter;
|
||||||
|
import org.jetbrains.uast.java.JavaConverter;
|
||||||
|
|
||||||
|
public class JavaLintLanguageExtension extends LintLanguageExtension {
|
||||||
|
@Override
|
||||||
|
public UastConverter getConverter() {
|
||||||
|
return JavaConverter.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,26 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ATTR_VALUE;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.tools.klint.detector.api.JavaContext;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
|
||||||
import com.android.tools.lint.detector.api.Location;
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
import com.google.common.base.Splitter;
|
import org.jetbrains.uast.UFile;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.ast.Identifier;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
import lombok.ast.StrictListAccessor;
|
|
||||||
import lombok.ast.TypeReference;
|
|
||||||
import lombok.ast.TypeReferencePart;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper for a Java parser. This allows tools integrating lint to map directly
|
* A wrapper for a Java parser. This allows tools integrating lint to map directly
|
||||||
@@ -56,475 +42,11 @@ public abstract class JavaParser {
|
|||||||
public static final String TYPE_BYTE = "byte"; //$NON-NLS-1$
|
public static final String TYPE_BYTE = "byte"; //$NON-NLS-1$
|
||||||
public static final String TYPE_NULL = "null"; //$NON-NLS-1$
|
public static final String TYPE_NULL = "null"; //$NON-NLS-1$
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare to parse the given contexts. This method will be called before
|
|
||||||
* a series of {@link #parseJava(JavaContext)} calls, which allows some
|
|
||||||
* parsers to do up front global computation in case they want to more
|
|
||||||
* efficiently process multiple files at the same time. This allows a single
|
|
||||||
* type-attribution pass for example, which is a lot more efficient than
|
|
||||||
* performing global type analysis over and over again for each individual
|
|
||||||
* file
|
|
||||||
*
|
|
||||||
* @param contexts a list of contexts to be parsed
|
|
||||||
*/
|
|
||||||
public abstract void prepareJavaParse(@NonNull List<JavaContext> contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the file pointed to by the given context.
|
|
||||||
*
|
|
||||||
* @param context the context pointing to the file to be parsed, typically
|
|
||||||
* via {@link Context#getContents()} but the file handle (
|
|
||||||
* {@link Context#file} can also be used to map to an existing
|
|
||||||
* editor buffer in the surrounding tool, etc)
|
|
||||||
* @return the compilation unit node for the file
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public abstract Node parseJava(@NonNull JavaContext context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link Location} for the given node
|
|
||||||
*
|
|
||||||
* @param context information about the file being parsed
|
|
||||||
* @param node the node to create a location for
|
|
||||||
* @return a location for the given node
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public abstract Location getLocation(@NonNull JavaContext context, @NonNull Node node);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a light-weight handle to a location for the given node. It can be
|
|
||||||
* turned into a full fledged location by
|
|
||||||
* {@link com.android.tools.lint.detector.api.Location.Handle#resolve()}.
|
|
||||||
*
|
|
||||||
* @param context the context providing the node
|
|
||||||
* @param node the node (element or attribute) to create a location handle
|
|
||||||
* for
|
|
||||||
* @return a location handle
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public abstract Location.Handle createLocationHandle(@NonNull JavaContext context,
|
|
||||||
@NonNull Node node);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose any data structures held for the given context.
|
* Dispose any data structures held for the given context.
|
||||||
* @param context information about the file previously parsed
|
* @param context information about the file previously parsed
|
||||||
* @param compilationUnit the compilation unit being disposed
|
* @param compilationUnit the compilation unit being disposed
|
||||||
*/
|
*/
|
||||||
public void dispose(@NonNull JavaContext context, @NonNull Node compilationUnit) {
|
public void dispose(@NonNull JavaContext context, @NonNull UFile compilationUnit) {
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispose any remaining data structures held for all contexts.
|
|
||||||
* Typically frees up any resources allocated by
|
|
||||||
* {@link #prepareJavaParse(List)}
|
|
||||||
*/
|
|
||||||
public void dispose() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the given expression node: computes the declaration for the given symbol
|
|
||||||
*
|
|
||||||
* @param context information about the file being parsed
|
|
||||||
* @param node the node to resolve
|
|
||||||
* @return a node representing the resolved fully type: class/interface/annotation,
|
|
||||||
* field, method or variable
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public abstract ResolvedNode resolve(@NonNull JavaContext context, @NonNull Node node);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the given type, if possible (which should be reachable from the compilation
|
|
||||||
* patch of the given node.
|
|
||||||
*
|
|
||||||
* @param context information about the file being parsed
|
|
||||||
* @param fullyQualifiedName the fully qualified name of the class to look up
|
|
||||||
* @return the class, or null if not found
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public ResolvedClass findClass(
|
|
||||||
@NonNull JavaContext context,
|
|
||||||
@NonNull String fullyQualifiedName) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type of the given node
|
|
||||||
*
|
|
||||||
* @param context information about the file being parsed
|
|
||||||
* @param node the node to look up the type for
|
|
||||||
* @return the type of the node, if known
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public abstract TypeDescriptor getType(@NonNull JavaContext context, @NonNull Node node);
|
|
||||||
|
|
||||||
/** A description of a type, such as a primitive int or the android.app.Activity class */
|
|
||||||
public abstract static class TypeDescriptor {
|
|
||||||
/**
|
|
||||||
* Returns the fully qualified name of the type, such as "int" or "android.app.Activity"
|
|
||||||
* */
|
|
||||||
@NonNull public abstract String getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the full signature of the type, which is normally the same as {@link #getName()}
|
|
||||||
* but for arrays can include []'s, for generic methods can include generics parameters
|
|
||||||
* etc
|
|
||||||
*/
|
|
||||||
@NonNull public abstract String getSignature();
|
|
||||||
|
|
||||||
public abstract boolean matchesName(@NonNull String name);
|
|
||||||
|
|
||||||
public abstract boolean matchesSignature(@NonNull String signature);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public TypeReference getNode() {
|
|
||||||
TypeReference typeReference = new TypeReference();
|
|
||||||
StrictListAccessor<TypeReferencePart, TypeReference> parts = typeReference.astParts();
|
|
||||||
for (String part : Splitter.on('.').split(getName())) {
|
|
||||||
Identifier identifier = Identifier.of(part);
|
|
||||||
parts.addToEnd(new TypeReferencePart().astIdentifier(identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** If the type is not primitive, returns the class of the type if known */
|
|
||||||
@Nullable
|
|
||||||
public abstract ResolvedClass getTypeClass();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract boolean equals(Object o);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience implementation of {@link TypeDescriptor} */
|
|
||||||
public static class DefaultTypeDescriptor extends TypeDescriptor {
|
|
||||||
|
|
||||||
private String mName;
|
|
||||||
|
|
||||||
public DefaultTypeDescriptor(String name) {
|
|
||||||
mName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String getSignature() {
|
|
||||||
return getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matchesName(@NonNull String name) {
|
|
||||||
return mName.equals(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matchesSignature(@NonNull String signature) {
|
|
||||||
return matchesName(signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getSignature();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public ResolvedClass getTypeClass() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (o == null || getClass() != o.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultTypeDescriptor that = (DefaultTypeDescriptor) o;
|
|
||||||
|
|
||||||
return !(mName != null ? !mName.equals(that.mName) : that.mName != null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return mName != null ? mName.hashCode() : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A resolved declaration from an AST Node reference */
|
|
||||||
public abstract static class ResolvedNode {
|
|
||||||
@NonNull
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
/** Returns the signature of the resolved node */
|
|
||||||
public abstract String getSignature();
|
|
||||||
|
|
||||||
public abstract int getModifiers();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getSignature();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns any annotations defined on this node */
|
|
||||||
@NonNull
|
|
||||||
public abstract Iterable<ResolvedAnnotation> getAnnotations();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for the annotation of the given type on this node
|
|
||||||
*
|
|
||||||
* @param type the fully qualified name of the annotation to check
|
|
||||||
* @return the annotation, or null if not found
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public ResolvedAnnotation getAnnotation(@NonNull String type) {
|
|
||||||
for (ResolvedAnnotation annotation : getAnnotations()) {
|
|
||||||
if (annotation.getType().matchesSignature(type)) {
|
|
||||||
return annotation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A resolved class declaration (class, interface, enumeration or annotation) */
|
|
||||||
public abstract static class ResolvedClass extends ResolvedNode {
|
|
||||||
/** Returns the fully qualified name of this class */
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
/** Returns the simple of this class */
|
|
||||||
@NonNull
|
|
||||||
public abstract String getSimpleName();
|
|
||||||
|
|
||||||
/** Returns the package name of this class */
|
|
||||||
@NonNull
|
|
||||||
public String getPackageName() {
|
|
||||||
String name = getName();
|
|
||||||
String simpleName = getSimpleName();
|
|
||||||
if (name.length() > simpleName.length() + 1) {
|
|
||||||
return name.substring(0, name.length() - simpleName.length() - 1);
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns whether this class' fully qualified name matches the given name */
|
|
||||||
public abstract boolean matches(@NonNull String name);
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public abstract ResolvedClass getSuperClass();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public abstract ResolvedClass getContainingClass();
|
|
||||||
|
|
||||||
public TypeDescriptor getType() {
|
|
||||||
return new DefaultTypeDescriptor(getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether this class extends the given name. If strict is true,
|
|
||||||
* it will not consider C extends C true.
|
|
||||||
*
|
|
||||||
* @param name the fully qualified class name
|
|
||||||
* @param strict if true, do not consider a class to be extending itself
|
|
||||||
* @return true if this class extends the given class
|
|
||||||
*/
|
|
||||||
public abstract boolean isSubclassOf(@NonNull String name, boolean strict);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract Iterable<ResolvedMethod> getConstructors();
|
|
||||||
|
|
||||||
/** Returns the methods defined in this class, and optionally any methods inherited from any superclasses as well */
|
|
||||||
@NonNull
|
|
||||||
public abstract Iterable<ResolvedMethod> getMethods(boolean includeInherited);
|
|
||||||
|
|
||||||
/** Returns the methods of a given name defined in this class, and optionally any methods inherited from any superclasses as well */
|
|
||||||
@NonNull
|
|
||||||
public abstract Iterable<ResolvedMethod> getMethods(@NonNull String name, boolean includeInherited);
|
|
||||||
|
|
||||||
/** Returns the named field defined in this class, or optionally inherited from a superclass */
|
|
||||||
@Nullable
|
|
||||||
public abstract ResolvedField getField(@NonNull String name, boolean includeInherited);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A method or constructor declaration */
|
|
||||||
public abstract static class ResolvedMethod extends ResolvedNode {
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
/** Returns whether this method name matches the given name */
|
|
||||||
public abstract boolean matches(@NonNull String name);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract ResolvedClass getContainingClass();
|
|
||||||
|
|
||||||
public abstract int getArgumentCount();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract TypeDescriptor getArgumentType(int index);
|
|
||||||
|
|
||||||
/** Returns true if the parameter at the given index matches the given type signature */
|
|
||||||
public boolean argumentMatchesType(int index, @NonNull String signature) {
|
|
||||||
return getArgumentType(index).matchesSignature(signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public abstract TypeDescriptor getReturnType();
|
|
||||||
|
|
||||||
public boolean isConstructor() {
|
|
||||||
return getReturnType() == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns any annotations defined on the given parameter of this method */
|
|
||||||
@NonNull
|
|
||||||
public abstract Iterable<ResolvedAnnotation> getParameterAnnotations(int index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for the annotation of the given type on the method
|
|
||||||
*
|
|
||||||
* @param type the fully qualified name of the annotation to check
|
|
||||||
* @param parameterIndex the index of the parameter to look up
|
|
||||||
* @return the annotation, or null if not found
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public ResolvedAnnotation getParameterAnnotation(@NonNull String type,
|
|
||||||
int parameterIndex) {
|
|
||||||
for (ResolvedAnnotation annotation : getParameterAnnotations(parameterIndex)) {
|
|
||||||
if (annotation.getType().matchesSignature(type)) {
|
|
||||||
return annotation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the super implementation of the given method, if any */
|
|
||||||
@Nullable
|
|
||||||
public ResolvedMethod getSuperMethod() {
|
|
||||||
ResolvedClass cls = getContainingClass().getSuperClass();
|
|
||||||
if (cls != null) {
|
|
||||||
String methodName = getName();
|
|
||||||
int argCount = getArgumentCount();
|
|
||||||
for (ResolvedMethod method : cls.getMethods(methodName, true)) {
|
|
||||||
if (argCount != method.getArgumentCount()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
boolean sameTypes = true;
|
|
||||||
for (int arg = 0; arg < argCount; arg++) {
|
|
||||||
if (!method.getArgumentType(arg).equals(getArgumentType(arg))) {
|
|
||||||
sameTypes = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sameTypes) {
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A field declaration */
|
|
||||||
public abstract static class ResolvedField extends ResolvedNode {
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
/** Returns whether this field name matches the given name */
|
|
||||||
public abstract boolean matches(@NonNull String name);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract TypeDescriptor getType();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract ResolvedClass getContainingClass();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public abstract Object getValue();
|
|
||||||
|
|
||||||
public String getContainingClassName() {
|
|
||||||
return getContainingClass().getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An annotation <b>reference</b>. Note that this refers to a usage of an annotation,
|
|
||||||
* not a declaraton of an annotation. You can call {@link #getClassType()} to
|
|
||||||
* find the declaration for the annotation.
|
|
||||||
*/
|
|
||||||
public abstract static class ResolvedAnnotation extends ResolvedNode {
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
/** Returns whether this field name matches the given name */
|
|
||||||
public abstract boolean matches(@NonNull String name);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract TypeDescriptor getType();
|
|
||||||
|
|
||||||
/** Returns the {@link ResolvedClass} which defines the annotation */
|
|
||||||
@Nullable
|
|
||||||
public abstract ResolvedClass getClassType();
|
|
||||||
|
|
||||||
public static class Value {
|
|
||||||
@NonNull public final String name;
|
|
||||||
@Nullable public final Object value;
|
|
||||||
|
|
||||||
public Value(@NonNull String name, @Nullable Object value) {
|
|
||||||
this.name = name;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract List<Value> getValues();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Object getValue(@NonNull String name) {
|
|
||||||
for (Value value : getValues()) {
|
|
||||||
if (name.equals(value.name)) {
|
|
||||||
return value.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Object getValue() {
|
|
||||||
return getValue(ATTR_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Iterable<ResolvedAnnotation> getAnnotations() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A local variable or parameter declaration */
|
|
||||||
public abstract static class ResolvedVariable extends ResolvedNode {
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
/** Returns whether this variable name matches the given name */
|
|
||||||
public abstract boolean matches(@NonNull String name);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract TypeDescriptor getType();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CLASS_FOLDER;
|
|
||||||
import static com.android.SdkConstants.DOT_AAR;
|
|
||||||
import static com.android.SdkConstants.DOT_JAR;
|
|
||||||
import static com.android.SdkConstants.GEN_FOLDER;
|
|
||||||
import static com.android.SdkConstants.LIBS_FOLDER;
|
|
||||||
import static com.android.SdkConstants.RES_FOLDER;
|
|
||||||
import static com.android.SdkConstants.SRC_FOLDER;
|
|
||||||
import static com.android.tools.lint.detector.api.LintUtils.endsWith;
|
|
||||||
|
|
||||||
import com.android.SdkConstants;
|
import com.android.SdkConstants;
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
@@ -35,21 +26,21 @@ import com.android.prefs.AndroidLocation;
|
|||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkVersionInfo;
|
import com.android.sdklib.SdkVersionInfo;
|
||||||
import com.android.sdklib.repository.local.LocalSdk;
|
import com.android.sdklib.repository.local.LocalSdk;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.TextFormat;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
import com.android.utils.XmlUtils;
|
import com.android.utils.XmlUtils;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
|
import org.jetbrains.uast.UastConverter;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
@@ -59,13 +50,10 @@ import java.io.IOException;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import static com.android.SdkConstants.*;
|
||||||
import java.util.HashMap;
|
import static com.android.tools.klint.detector.api.LintUtils.endsWith;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the tool embedding the lint analyzer. IDEs and other tools
|
* Information about the tool embedding the lint analyzer. IDEs and other tools
|
||||||
@@ -153,19 +141,6 @@ public abstract class LintClient {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public abstract XmlParser getXmlParser();
|
public abstract XmlParser getXmlParser();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link JavaParser} to use to parse Java
|
|
||||||
*
|
|
||||||
* @param project the project to parse, if known (this can be used to look up
|
|
||||||
* the class path for type attribution etc, and it can also be used
|
|
||||||
* to more efficiently process a set of files, for example to
|
|
||||||
* perform type attribution for multiple units in a single pass)
|
|
||||||
* @return a new {@link JavaParser}, or null if this client does not
|
|
||||||
* support Java analysis
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public abstract JavaParser getJavaParser(@Nullable Project project);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an optimal detector, if applicable. By default, just returns the
|
* Returns an optimal detector, if applicable. By default, just returns the
|
||||||
* original detector, but tools can replace detectors using this hook with a version
|
* original detector, but tools can replace detectors using this hook with a version
|
||||||
@@ -406,6 +381,15 @@ public abstract class LintClient {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public com.intellij.openapi.project.Project getProject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UastConverter> getConverters() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about class paths (sources, class files and libraries)
|
* Information about class paths (sources, class files and libraries)
|
||||||
* usually associated with a project.
|
* usually associated with a project.
|
||||||
|
|||||||
@@ -14,24 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ATTR_IGNORE;
|
|
||||||
import static com.android.SdkConstants.CLASS_CONSTRUCTOR;
|
|
||||||
import static com.android.SdkConstants.CONSTRUCTOR_NAME;
|
|
||||||
import static com.android.SdkConstants.DOT_CLASS;
|
|
||||||
import static com.android.SdkConstants.DOT_JAR;
|
|
||||||
import static com.android.SdkConstants.DOT_JAVA;
|
|
||||||
import static com.android.SdkConstants.FD_GRADLE_WRAPPER;
|
|
||||||
import static com.android.SdkConstants.FN_GRADLE_WRAPPER_PROPERTIES;
|
|
||||||
import static com.android.SdkConstants.FN_LOCAL_PROPERTIES;
|
|
||||||
import static com.android.SdkConstants.RES_FOLDER;
|
|
||||||
import static com.android.SdkConstants.SUPPRESS_ALL;
|
|
||||||
import static com.android.SdkConstants.SUPPRESS_LINT;
|
|
||||||
import static com.android.SdkConstants.TOOLS_URI;
|
|
||||||
import static com.android.ide.common.resources.configuration.FolderConfiguration.QUALIFIER_SPLITTER;
|
|
||||||
import static com.android.tools.lint.detector.api.LintUtils.isAnonymousClass;
|
|
||||||
import static java.io.File.separator;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
@@ -40,79 +23,47 @@ import com.android.ide.common.res2.ResourceItem;
|
|||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.repository.local.LocalSdk;
|
import com.android.sdklib.repository.local.LocalSdk;
|
||||||
import com.android.tools.lint.client.api.LintListener.EventType;
|
import com.android.tools.klint.detector.api.ClassContext;
|
||||||
import com.android.tools.lint.detector.api.ClassContext;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.JavaContext;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.ResourceContext;
|
||||||
import com.android.tools.lint.detector.api.ResourceContext;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
import com.android.tools.lint.detector.api.TextFormat;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.*;
|
||||||
import com.google.common.collect.Lists;
|
import com.sun.istack.internal.NotNull;
|
||||||
import com.google.common.collect.Maps;
|
import org.jetbrains.uast.*;
|
||||||
import com.google.common.collect.Multimap;
|
import org.jetbrains.uast.check.UastChecker;
|
||||||
import com.google.common.collect.Sets;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
import org.jetbrains.uast.java.JavaUastCallKinds;
|
||||||
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.*;
|
||||||
import org.objectweb.asm.tree.AnnotationNode;
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
import org.objectweb.asm.tree.FieldInsnNode;
|
|
||||||
import org.objectweb.asm.tree.FieldNode;
|
|
||||||
import org.objectweb.asm.tree.InsnList;
|
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.ArrayDeque;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.IdentityHashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import lombok.ast.Annotation;
|
import static com.android.SdkConstants.*;
|
||||||
import lombok.ast.AnnotationElement;
|
import static com.android.ide.common.resources.configuration.FolderConfiguration.QUALIFIER_SPLITTER;
|
||||||
import lombok.ast.AnnotationValue;
|
import static java.io.File.separator;
|
||||||
import lombok.ast.ArrayInitializer;
|
|
||||||
import lombok.ast.ClassDeclaration;
|
|
||||||
import lombok.ast.ConstructorDeclaration;
|
|
||||||
import lombok.ast.Expression;
|
|
||||||
import lombok.ast.MethodDeclaration;
|
|
||||||
import lombok.ast.Modifiers;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
import lombok.ast.StrictListAccessor;
|
|
||||||
import lombok.ast.StringLiteral;
|
|
||||||
import lombok.ast.TypeReference;
|
|
||||||
import lombok.ast.VariableDefinition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes Android projects and files
|
* Analyzes Android projects and files
|
||||||
@@ -415,7 +366,7 @@ public class LintDriver {
|
|||||||
mScope = Scope.infer(projects);
|
mScope = Scope.infer(projects);
|
||||||
}
|
}
|
||||||
|
|
||||||
fireEvent(EventType.STARTING, null);
|
fireEvent(LintListener.EventType.STARTING, null);
|
||||||
|
|
||||||
for (Project project : projects) {
|
for (Project project : projects) {
|
||||||
mPhase = 1;
|
mPhase = 1;
|
||||||
@@ -438,7 +389,7 @@ public class LintDriver {
|
|||||||
runExtraPhases(project, main);
|
runExtraPhases(project, main);
|
||||||
}
|
}
|
||||||
|
|
||||||
fireEvent(mCanceled ? EventType.CANCELED : EventType.COMPLETED, null);
|
fireEvent(mCanceled ? LintListener.EventType.CANCELED : LintListener.EventType.COMPLETED, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerCustomRules(Collection<Project> projects) {
|
private void registerCustomRules(Collection<Project> projects) {
|
||||||
@@ -484,7 +435,7 @@ public class LintDriver {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
mPhase++;
|
mPhase++;
|
||||||
fireEvent(EventType.NEW_PHASE,
|
fireEvent(LintListener.EventType.NEW_PHASE,
|
||||||
new Context(this, project, null, project.getDir()));
|
new Context(this, project, null, project.getDir()));
|
||||||
|
|
||||||
// Narrow the scope down to the set of scopes requested by
|
// Narrow the scope down to the set of scopes requested by
|
||||||
@@ -629,16 +580,16 @@ public class LintDriver {
|
|||||||
assert detector instanceof Detector.XmlScanner : detector;
|
assert detector instanceof Detector.XmlScanner : detector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<Detector> javaCodeDetectors = mScopeDetectors.get(Scope.ALL_JAVA_FILES);
|
List<Detector> javaCodeDetectors = mScopeDetectors.get(Scope.ALL_SOURCE_FILES);
|
||||||
if (javaCodeDetectors != null) {
|
if (javaCodeDetectors != null) {
|
||||||
for (Detector detector : javaCodeDetectors) {
|
for (Detector detector : javaCodeDetectors) {
|
||||||
assert detector instanceof Detector.JavaScanner : detector;
|
assert (detector instanceof UastScanner) : detector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<Detector> javaFileDetectors = mScopeDetectors.get(Scope.JAVA_FILE);
|
List<Detector> javaFileDetectors = mScopeDetectors.get(Scope.SOURCE_FILE);
|
||||||
if (javaFileDetectors != null) {
|
if (javaFileDetectors != null) {
|
||||||
for (Detector detector : javaFileDetectors) {
|
for (Detector detector : javaFileDetectors) {
|
||||||
assert detector instanceof Detector.JavaScanner : detector;
|
assert (detector instanceof UastScanner) : detector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,7 +812,7 @@ public class LintDriver {
|
|||||||
File projectDir = project.getDir();
|
File projectDir = project.getDir();
|
||||||
|
|
||||||
Context projectContext = new Context(this, project, null, projectDir);
|
Context projectContext = new Context(this, project, null, projectDir);
|
||||||
fireEvent(EventType.SCANNING_PROJECT, projectContext);
|
fireEvent(LintListener.EventType.SCANNING_PROJECT, projectContext);
|
||||||
|
|
||||||
List<Project> allLibraries = project.getAllLibraries();
|
List<Project> allLibraries = project.getAllLibraries();
|
||||||
Set<Project> allProjects = new HashSet<Project>(allLibraries.size() + 1);
|
Set<Project> allProjects = new HashSet<Project>(allLibraries.size() + 1);
|
||||||
@@ -885,7 +836,7 @@ public class LintDriver {
|
|||||||
List<Project> libraries = project.getAllLibraries();
|
List<Project> libraries = project.getAllLibraries();
|
||||||
for (Project library : libraries) {
|
for (Project library : libraries) {
|
||||||
Context libraryContext = new Context(this, library, project, projectDir);
|
Context libraryContext = new Context(this, library, project, projectDir);
|
||||||
fireEvent(EventType.SCANNING_LIBRARY_PROJECT, libraryContext);
|
fireEvent(LintListener.EventType.SCANNING_LIBRARY_PROJECT, libraryContext);
|
||||||
mCurrentProject = library;
|
mCurrentProject = library;
|
||||||
|
|
||||||
for (Detector check : mApplicableDetectors) {
|
for (Detector check : mApplicableDetectors) {
|
||||||
@@ -954,7 +905,7 @@ public class LintDriver {
|
|||||||
if (detectors != null) {
|
if (detectors != null) {
|
||||||
ResourceVisitor v = new ResourceVisitor(parser, detectors,
|
ResourceVisitor v = new ResourceVisitor(parser, detectors,
|
||||||
null);
|
null);
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
v.visitFile(context, manifestFile);
|
v.visitFile(context, manifestFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1014,9 +965,9 @@ public class LintDriver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mScope.contains(Scope.JAVA_FILE) || mScope.contains(Scope.ALL_JAVA_FILES)) {
|
if (mScope.contains(Scope.SOURCE_FILE) || mScope.contains(Scope.ALL_SOURCE_FILES)) {
|
||||||
List<Detector> checks = union(mScopeDetectors.get(Scope.JAVA_FILE),
|
List<Detector> checks = union(mScopeDetectors.get(Scope.SOURCE_FILE),
|
||||||
mScopeDetectors.get(Scope.ALL_JAVA_FILES));
|
mScopeDetectors.get(Scope.ALL_SOURCE_FILES));
|
||||||
if (checks != null && !checks.isEmpty()) {
|
if (checks != null && !checks.isEmpty()) {
|
||||||
List<File> files = project.getSubset();
|
List<File> files = project.getSubset();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
@@ -1111,7 +1062,7 @@ public class LintDriver {
|
|||||||
List<File> files = project.getProguardFiles();
|
List<File> files = project.getProguardFiles();
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
Context context = new Context(this, project, main, file);
|
Context context = new Context(this, project, main, file);
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
for (Detector detector : detectors) {
|
for (Detector detector : detectors) {
|
||||||
if (detector.appliesTo(context, file)) {
|
if (detector.appliesTo(context, file)) {
|
||||||
detector.beforeCheckFile(context);
|
detector.beforeCheckFile(context);
|
||||||
@@ -1137,7 +1088,7 @@ public class LintDriver {
|
|||||||
File file = new File(project.getDir(), relativePath);
|
File file = new File(project.getDir(), relativePath);
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
Context context = new Context(this, project, main, file);
|
Context context = new Context(this, project, main, file);
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
for (Detector detector : detectors) {
|
for (Detector detector : detectors) {
|
||||||
if (detector.appliesTo(context, file)) {
|
if (detector.appliesTo(context, file)) {
|
||||||
detector.beforeCheckFile(context);
|
detector.beforeCheckFile(context);
|
||||||
@@ -1476,12 +1427,6 @@ public class LintDriver {
|
|||||||
@Nullable Project main,
|
@Nullable Project main,
|
||||||
@NonNull List<File> sourceFolders,
|
@NonNull List<File> sourceFolders,
|
||||||
@NonNull List<Detector> checks) {
|
@NonNull List<Detector> checks) {
|
||||||
JavaParser javaParser = mClient.getJavaParser(project);
|
|
||||||
if (javaParser == null) {
|
|
||||||
mClient.log(null, "No java parser provided to lint: not running Java checks");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert !checks.isEmpty();
|
assert !checks.isEmpty();
|
||||||
|
|
||||||
// Gather all Java source files in a single pass; more efficient.
|
// Gather all Java source files in a single pass; more efficient.
|
||||||
@@ -1490,22 +1435,39 @@ public class LintDriver {
|
|||||||
gatherJavaFiles(folder, sources);
|
gatherJavaFiles(folder, sources);
|
||||||
}
|
}
|
||||||
if (!sources.isEmpty()) {
|
if (!sources.isEmpty()) {
|
||||||
JavaVisitor visitor = new JavaVisitor(javaParser, checks);
|
|
||||||
List<JavaContext> contexts = Lists.newArrayListWithExpectedSize(sources.size());
|
List<JavaContext> contexts = Lists.newArrayListWithExpectedSize(sources.size());
|
||||||
for (File file : sources) {
|
for (File file : sources) {
|
||||||
JavaContext context = new JavaContext(this, project, main, file, javaParser);
|
JavaContext context = new JavaContext(this, project, main, file, javaParser);
|
||||||
contexts.add(context);
|
contexts.add(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.prepare(contexts);
|
com.intellij.openapi.project.Project ideaProject = mClient.getProject();
|
||||||
|
if (ideaProject == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<UastConverter> converters = mClient.getConverters();
|
||||||
|
|
||||||
for (JavaContext context : contexts) {
|
for (JavaContext context : contexts) {
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
visitor.visitFile(context);
|
|
||||||
|
for (Detector check : checks) {
|
||||||
|
if (check instanceof UastScanner) {
|
||||||
|
UastScanner scanner = (UastScanner) check;
|
||||||
|
UastVisitor customVisitor = scanner.createUastVisitor(context);
|
||||||
|
if (customVisitor != null) {
|
||||||
|
UastChecker.INSTANCE.checkWithCustomHandler(
|
||||||
|
ideaProject, context.file, converters, customVisitor);
|
||||||
|
} else {
|
||||||
|
UastChecker.INSTANCE.check(
|
||||||
|
ideaProject, context.file, (UastScanner)check, converters, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mCanceled) {
|
if (mCanceled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visitor.dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1514,41 +1476,52 @@ public class LintDriver {
|
|||||||
@Nullable Project main,
|
@Nullable Project main,
|
||||||
@NonNull List<Detector> checks,
|
@NonNull List<Detector> checks,
|
||||||
@NonNull List<File> files) {
|
@NonNull List<File> files) {
|
||||||
|
List<UastScanner> uastDetectors = new ArrayList<UastScanner>();
|
||||||
|
|
||||||
JavaParser javaParser = mClient.getJavaParser(project);
|
for (Detector check : checks) {
|
||||||
if (javaParser == null) {
|
if (check instanceof UastScanner) {
|
||||||
mClient.log(null, "No java parser provided to lint: not running Java checks");
|
uastDetectors.add((UastScanner) check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkWithUastDetectors(project, main, uastDetectors, files);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkWithUastDetectors(
|
||||||
|
@NotNull Project project,
|
||||||
|
@Nullable Project main,
|
||||||
|
@NotNull List<UastScanner> detectors,
|
||||||
|
@NotNull List<File> files) {
|
||||||
|
com.intellij.openapi.project.Project intellijProject = mClient.getProject();
|
||||||
|
if (intellijProject == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaVisitor visitor = new JavaVisitor(javaParser, checks);
|
UastChecker checker = UastChecker.INSTANCE;
|
||||||
|
List<UastConverter> converters = project.getClient().getConverters();
|
||||||
|
|
||||||
List<JavaContext> contexts = Lists.newArrayListWithExpectedSize(files.size());
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
if (file.isFile() && file.getPath().endsWith(DOT_JAVA)) {
|
if (!file.isFile()) {
|
||||||
contexts.add(new JavaContext(this, project, main, file, javaParser));
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String path = file.getPath();
|
||||||
|
if (!path.endsWith(DOT_JAVA) && !UastConverterUtils.isFileSupported(converters, path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaContext
|
||||||
|
context = new JavaContext(this, project, main, file);
|
||||||
|
|
||||||
|
for (UastScanner detector : detectors) {
|
||||||
|
UastVisitor customHandler = detector.createUastVisitor(context);
|
||||||
|
if (customHandler != null) {
|
||||||
|
checker.checkWithCustomHandler(intellijProject, file, converters, customHandler);
|
||||||
|
} else {
|
||||||
|
checker.check(intellijProject, file, detector, converters, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contexts.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
visitor.prepare(contexts);
|
|
||||||
|
|
||||||
if (mCanceled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (JavaContext context : contexts) {
|
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
|
||||||
visitor.visitFile(context);
|
|
||||||
if (mCanceled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visitor.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void gatherJavaFiles(@NonNull File dir, @NonNull List<File> result) {
|
private static void gatherJavaFiles(@NonNull File dir, @NonNull List<File> result) {
|
||||||
@@ -1666,7 +1639,7 @@ public class LintDriver {
|
|||||||
if (dirChecks != null && !dirChecks.isEmpty()) {
|
if (dirChecks != null && !dirChecks.isEmpty()) {
|
||||||
ResourceContext context = new ResourceContext(this, project, main, dir, type);
|
ResourceContext context = new ResourceContext(this, project, main, dir, type);
|
||||||
String folderName = dir.getName();
|
String folderName = dir.getName();
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
for (Detector check : dirChecks) {
|
for (Detector check : dirChecks) {
|
||||||
if (check.appliesTo(type)) {
|
if (check.appliesTo(type)) {
|
||||||
check.beforeCheckFile(context);
|
check.beforeCheckFile(context);
|
||||||
@@ -1693,11 +1666,11 @@ public class LintDriver {
|
|||||||
if (LintUtils.isXmlFile(file)) {
|
if (LintUtils.isXmlFile(file)) {
|
||||||
XmlContext context = new XmlContext(this, project, main, file, type,
|
XmlContext context = new XmlContext(this, project, main, file, type,
|
||||||
visitor.getParser());
|
visitor.getParser());
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
visitor.visitFile(context, file);
|
visitor.visitFile(context, file);
|
||||||
} else if (binaryChecks != null && LintUtils.isBitmapFile(file)) {
|
} else if (binaryChecks != null && LintUtils.isBitmapFile(file)) {
|
||||||
ResourceContext context = new ResourceContext(this, project, main, file, type);
|
ResourceContext context = new ResourceContext(this, project, main, file, type);
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
visitor.visitBinaryResource(context);
|
visitor.visitBinaryResource(context);
|
||||||
}
|
}
|
||||||
if (mCanceled) {
|
if (mCanceled) {
|
||||||
@@ -1739,7 +1712,7 @@ public class LintDriver {
|
|||||||
if (visitor != null) {
|
if (visitor != null) {
|
||||||
XmlContext context = new XmlContext(this, project, main, file, type,
|
XmlContext context = new XmlContext(this, project, main, file, type,
|
||||||
visitor.getParser());
|
visitor.getParser());
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
visitor.visitFile(context, file);
|
visitor.visitFile(context, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1752,7 +1725,7 @@ public class LintDriver {
|
|||||||
if (visitor != null) {
|
if (visitor != null) {
|
||||||
ResourceContext context = new ResourceContext(this, project, main, file,
|
ResourceContext context = new ResourceContext(this, project, main, file,
|
||||||
type);
|
type);
|
||||||
fireEvent(EventType.SCANNING_FILE, context);
|
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||||
visitor.visitBinaryResource(context);
|
visitor.visitBinaryResource(context);
|
||||||
if (mCanceled) {
|
if (mCanceled) {
|
||||||
return;
|
return;
|
||||||
@@ -1920,12 +1893,6 @@ public class LintDriver {
|
|||||||
return mDelegate.getProject(dir, referenceDir);
|
return mDelegate.getProject(dir, referenceDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public JavaParser getJavaParser(@Nullable Project project) {
|
|
||||||
return mDelegate.getJavaParser(project);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File findResource(@NonNull String relativePath) {
|
public File findResource(@NonNull String relativePath) {
|
||||||
return mDelegate.findResource(relativePath);
|
return mDelegate.findResource(relativePath);
|
||||||
@@ -1939,7 +1906,7 @@ public class LintDriver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
protected ClassPathInfo getClassPath(@NonNull Project project) {
|
protected LintClient.ClassPathInfo getClassPath(@NonNull Project project) {
|
||||||
return mDelegate.getClassPath(project);
|
return mDelegate.getClassPath(project);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2069,6 +2036,17 @@ public class LintDriver {
|
|||||||
public void closeConnection(@NonNull URLConnection connection) throws IOException {
|
public void closeConnection(@NonNull URLConnection connection) throws IOException {
|
||||||
mDelegate.closeConnection(connection);
|
mDelegate.closeConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.intellij.openapi.project.Project getProject() {
|
||||||
|
return mDelegate.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UastConverter> getConverters() {
|
||||||
|
return mDelegate.getConverters();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2140,7 +2118,7 @@ public class LintDriver {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (classNode.outerClass != null && classNode.outerMethod == null
|
} else if (classNode.outerClass != null && classNode.outerMethod == null
|
||||||
&& isAnonymousClass(classNode)) {
|
&& LintUtils.isAnonymousClass(classNode)) {
|
||||||
if (isSuppressed(issue, classNode)) {
|
if (isSuppressed(issue, classNode)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2251,7 +2229,7 @@ public class LintDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (classNode.outerClass != null && classNode.outerMethod == null
|
if (classNode.outerClass != null && classNode.outerMethod == null
|
||||||
&& isAnonymousClass(classNode)) {
|
&& LintUtils.isAnonymousClass(classNode)) {
|
||||||
ClassNode outer = getOuterClassNode(classNode);
|
ClassNode outer = getOuterClassNode(classNode);
|
||||||
if (outer != null) {
|
if (outer != null) {
|
||||||
MethodNode m = findMethod(outer, CONSTRUCTOR_NAME, false);
|
MethodNode m = findMethod(outer, CONSTRUCTOR_NAME, false);
|
||||||
@@ -2347,44 +2325,31 @@ public class LintDriver {
|
|||||||
* issue in this class
|
* issue in this class
|
||||||
*/
|
*/
|
||||||
public boolean isSuppressed(@Nullable JavaContext context, @NonNull Issue issue,
|
public boolean isSuppressed(@Nullable JavaContext context, @NonNull Issue issue,
|
||||||
@Nullable Node scope) {
|
@Nullable UElement scope) {
|
||||||
boolean checkComments = mClient.checkForSuppressComments() &&
|
boolean checkComments = mClient.checkForSuppressComments() &&
|
||||||
context != null && context.containsCommentSuppress();
|
context != null && context.containsCommentSuppress();
|
||||||
while (scope != null) {
|
while (scope != null) {
|
||||||
Class<? extends Node> type = scope.getClass();
|
if (scope instanceof UVariable) {
|
||||||
// The Lombok AST uses a flat hierarchy of node type implementation classes
|
UVariable declaration = (UVariable) scope;
|
||||||
// so no need to do instanceof stuff here.
|
if (isUastSuppressed(issue, declaration.getAnnotations())) {
|
||||||
if (type == VariableDefinition.class) {
|
|
||||||
// Variable
|
|
||||||
VariableDefinition declaration = (VariableDefinition) scope;
|
|
||||||
if (isSuppressed(issue, declaration.astModifiers())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (type == MethodDeclaration.class) {
|
} else if (scope instanceof UFunction) {
|
||||||
// Method
|
UFunction declaration = (UFunction) scope;
|
||||||
// Look for annotations on the method
|
if (isUastSuppressed(issue, declaration.getAnnotations())) {
|
||||||
MethodDeclaration declaration = (MethodDeclaration) scope;
|
|
||||||
if (isSuppressed(issue, declaration.astModifiers())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (type == ConstructorDeclaration.class) {
|
} else if (scope instanceof UClass) {
|
||||||
// Constructor
|
UClass declaration = (UClass) scope;
|
||||||
// Look for annotations on the method
|
if (isUastSuppressed(issue, declaration.getAnnotations())) {
|
||||||
ConstructorDeclaration declaration = (ConstructorDeclaration) scope;
|
|
||||||
if (isSuppressed(issue, declaration.astModifiers())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (type == ClassDeclaration.class) {
|
|
||||||
// Class
|
|
||||||
ClassDeclaration declaration = (ClassDeclaration) scope;
|
|
||||||
if (isSuppressed(issue, declaration.astModifiers())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkComments && context.isSuppressedWithComment(scope, issue)) {
|
//TODO check comments
|
||||||
return true;
|
//if (checkComments && context.isSuppressedWithComment(scope, issue)) {
|
||||||
}
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
scope = scope.getParent();
|
scope = scope.getParent();
|
||||||
}
|
}
|
||||||
@@ -2401,47 +2366,27 @@ public class LintDriver {
|
|||||||
* @return true if the issue or all issues should be suppressed for this
|
* @return true if the issue or all issues should be suppressed for this
|
||||||
* modifier
|
* modifier
|
||||||
*/
|
*/
|
||||||
private static boolean isSuppressed(@Nullable Issue issue, @Nullable Modifiers modifiers) {
|
private static boolean isUastSuppressed(@Nullable Issue issue, @Nullable List<UAnnotation> annotations) {
|
||||||
if (modifiers == null) {
|
for (UAnnotation annotation : annotations) {
|
||||||
return false;
|
if (annotation.matchesName(SUPPRESS_LINT)
|
||||||
}
|
|| annotation.matchesName("SuppressWarnings")) { //$NON-NLS-1$
|
||||||
StrictListAccessor<Annotation, Modifiers> annotations = modifiers.astAnnotations();
|
List<UNamedExpression> values = annotation.getValueArguments();
|
||||||
if (annotations == null) {
|
for (UNamedExpression element : values) {
|
||||||
return false;
|
UExpression valueNode = element.getExpression();
|
||||||
}
|
String value = UastLiteralUtils.getValueIfStringLiteral(valueNode);
|
||||||
|
if (value != null) {
|
||||||
for (Annotation annotation : annotations) {
|
if (matches(issue, value)) {
|
||||||
TypeReference t = annotation.astAnnotationTypeReference();
|
return true;
|
||||||
String typeName = t.getTypeName();
|
|
||||||
if (typeName.endsWith(SUPPRESS_LINT)
|
|
||||||
|| typeName.endsWith("SuppressWarnings")) { //$NON-NLS-1$
|
|
||||||
StrictListAccessor<AnnotationElement, Annotation> values =
|
|
||||||
annotation.astElements();
|
|
||||||
if (values != null) {
|
|
||||||
for (AnnotationElement element : values) {
|
|
||||||
AnnotationValue valueNode = element.astValue();
|
|
||||||
if (valueNode == null) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (valueNode instanceof StringLiteral) {
|
} else if (valueNode instanceof UCallExpression
|
||||||
StringLiteral literal = (StringLiteral) valueNode;
|
&& ((UCallExpression)valueNode).getKind() == JavaUastCallKinds.ARRAY_INITIALIZER) {
|
||||||
String value = literal.astValue();
|
UCallExpression array = (UCallExpression) valueNode;
|
||||||
if (matches(issue, value)) {
|
List<UExpression> expressions = array.getValueArguments();
|
||||||
return true;
|
for (UExpression arrayElement : expressions) {
|
||||||
}
|
String elementValue = UastLiteralUtils.getValueIfStringLiteral(arrayElement);
|
||||||
} else if (valueNode instanceof ArrayInitializer) {
|
if (elementValue != null) {
|
||||||
ArrayInitializer array = (ArrayInitializer) valueNode;
|
if (matches(issue, elementValue)) {
|
||||||
StrictListAccessor<Expression, ArrayInitializer> expressions =
|
return true;
|
||||||
array.astExpressions();
|
|
||||||
if (expressions == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (Expression arrayElement : expressions) {
|
|
||||||
if (arrayElement instanceof StringLiteral) {
|
|
||||||
String value = ((StringLiteral) arrayElement).astValue();
|
|
||||||
if (matches(issue, value)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.klint.client.api;
|
||||||
|
|
||||||
|
import com.android.annotations.NonNull;
|
||||||
|
import com.android.annotations.Nullable;
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import org.jetbrains.uast.UastConverter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class LintLanguageExtension {
|
||||||
|
public static final ExtensionPointName<LintLanguageExtension> EP_NAME =
|
||||||
|
ExtensionPointName.create("com.android.tools.lint.client.api.lintLanguageExtension");
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract UastConverter getConverter();
|
||||||
|
|
||||||
|
public static boolean isFileSupported(@Nullable Project project, String path) {
|
||||||
|
LintLanguageExtension[] extensions = getExtensions(project);
|
||||||
|
for (LintLanguageExtension ext : extensions) {
|
||||||
|
if (ext.getConverter().isFileSupported(path)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<UastConverter> getConverters(@Nullable Project project) {
|
||||||
|
if (project == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
LintLanguageExtension[] languageExtensions = project.getExtensions(EP_NAME);
|
||||||
|
List<UastConverter> converters = new ArrayList<UastConverter>(languageExtensions.length);
|
||||||
|
for (LintLanguageExtension extension : languageExtensions) {
|
||||||
|
converters.add(extension.getConverter());
|
||||||
|
}
|
||||||
|
return converters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LintLanguageExtension[] getExtensions(@Nullable Project project) {
|
||||||
|
if (project == null) {
|
||||||
|
return new LintLanguageExtension[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return project.getExtensions(EP_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,11 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,12 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
+12
-20
@@ -13,30 +13,22 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
|
|
||||||
import static com.android.SdkConstants.DOT_CLASS;
|
|
||||||
import static com.android.SdkConstants.DOT_JAVA;
|
|
||||||
import static com.android.SdkConstants.DOT_XML;
|
|
||||||
import static com.android.SdkConstants.FD_ASSETS;
|
|
||||||
import static com.android.tools.lint.detector.api.Detector.OtherFileScanner;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.utils.SdkUtils;
|
import com.android.utils.SdkUtils;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.EnumSet;
|
import static com.android.SdkConstants.*;
|
||||||
import java.util.List;
|
import static com.android.tools.klint.detector.api.Detector.OtherFileScanner;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visitor for "other" files: files that aren't java sources,
|
* Visitor for "other" files: files that aren't java sources,
|
||||||
@@ -102,7 +94,7 @@ class OtherFileVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scopes.contains(Scope.JAVA_FILE)) {
|
if (scopes.contains(Scope.SOURCE_FILE)) {
|
||||||
if (subset != null && !subset.isEmpty()) {
|
if (subset != null && !subset.isEmpty()) {
|
||||||
List<File> files = new ArrayList<File>(subset.size());
|
List<File> files = new ArrayList<File>(subset.size());
|
||||||
for (File file : subset) {
|
for (File file : subset) {
|
||||||
@@ -111,7 +103,7 @@ class OtherFileVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
mFiles.put(Scope.JAVA_FILE, files);
|
mFiles.put(Scope.SOURCE_FILE, files);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
List<File> files = Lists.newArrayListWithExpectedSize(100);
|
List<File> files = Lists.newArrayListWithExpectedSize(100);
|
||||||
@@ -119,7 +111,7 @@ class OtherFileVisitor {
|
|||||||
collectFiles(files, srcFolder);
|
collectFiles(files, srcFolder);
|
||||||
}
|
}
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
mFiles.put(Scope.JAVA_FILE, files);
|
mFiles.put(Scope.SOURCE_FILE, files);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,30 +14,20 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Detector.XmlScanner;
|
import com.android.tools.klint.detector.api.Detector.XmlScanner;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.ResourceContext;
|
import com.android.tools.klint.detector.api.ResourceContext;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
import org.w3c.dom.*;
|
||||||
import org.w3c.dom.Attr;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.NamedNodeMap;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.RandomAccess;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialized visitor for running detectors on resources: typically XML documents,
|
* Specialized visitor for running detectors on resources: typically XML documents,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
|
|||||||
@@ -14,15 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.client.api;
|
package com.android.tools.klint.client.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
|
|||||||
@@ -14,34 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CONSTRUCTOR_NAME;
|
|
||||||
import static com.android.SdkConstants.DOT_CLASS;
|
|
||||||
import static com.android.SdkConstants.DOT_JAVA;
|
|
||||||
import static com.android.tools.lint.detector.api.Location.SearchDirection.BACKWARD;
|
|
||||||
import static com.android.tools.lint.detector.api.Location.SearchDirection.EOL_BACKWARD;
|
|
||||||
import static com.android.tools.lint.detector.api.Location.SearchDirection.FORWARD;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
import com.android.tools.klint.client.api.LintDriver;
|
||||||
import com.android.tools.lint.detector.api.Location.SearchDirection;
|
|
||||||
import com.android.tools.lint.detector.api.Location.SearchHints;
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.*;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
import org.objectweb.asm.tree.FieldNode;
|
|
||||||
import org.objectweb.asm.tree.LineNumberNode;
|
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Context} used when checking .class files.
|
* A {@link Context} used when checking .class files.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -261,7 +248,7 @@ public class ClassContext extends Context {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public Location getLocationForLine(int line, @Nullable String patternStart,
|
public Location getLocationForLine(int line, @Nullable String patternStart,
|
||||||
@Nullable String patternEnd, @Nullable SearchHints hints) {
|
@Nullable String patternEnd, @Nullable Location.SearchHints hints) {
|
||||||
File sourceFile = getSourceFile();
|
File sourceFile = getSourceFile();
|
||||||
if (sourceFile != null) {
|
if (sourceFile != null) {
|
||||||
// ASM line numbers are 1-based, and lint line numbers are 0-based
|
// ASM line numbers are 1-based, and lint line numbers are 0-based
|
||||||
@@ -515,7 +502,7 @@ public class ClassContext extends Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return getLocationForLine(findLineNumber(classNode), pattern, null,
|
return getLocationForLine(findLineNumber(classNode), pattern, null,
|
||||||
SearchHints.create(BACKWARD).matchJavaSymbol());
|
Location.SearchHints.create(Location.SearchDirection.BACKWARD).matchJavaSymbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -556,21 +543,21 @@ public class ClassContext extends Context {
|
|||||||
// to find a method, look up the corresponding line number then search
|
// to find a method, look up the corresponding line number then search
|
||||||
// around it for a suitable tag, such as the class name.
|
// around it for a suitable tag, such as the class name.
|
||||||
String pattern;
|
String pattern;
|
||||||
SearchDirection searchMode;
|
Location.SearchDirection searchMode;
|
||||||
if (methodNode.name.equals(CONSTRUCTOR_NAME)) {
|
if (methodNode.name.equals(CONSTRUCTOR_NAME)) {
|
||||||
searchMode = EOL_BACKWARD;
|
searchMode = Location.SearchDirection.EOL_BACKWARD;
|
||||||
if (isAnonymousClass(classNode.name)) {
|
if (isAnonymousClass(classNode.name)) {
|
||||||
pattern = classNode.superName.substring(classNode.superName.lastIndexOf('/') + 1);
|
pattern = classNode.superName.substring(classNode.superName.lastIndexOf('/') + 1);
|
||||||
} else {
|
} else {
|
||||||
pattern = classNode.name.substring(classNode.name.lastIndexOf('$') + 1);
|
pattern = classNode.name.substring(classNode.name.lastIndexOf('$') + 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
searchMode = BACKWARD;
|
searchMode = Location.SearchDirection.BACKWARD;
|
||||||
pattern = methodNode.name;
|
pattern = methodNode.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getLocationForLine(findLineNumber(methodNode), pattern, null,
|
return getLocationForLine(findLineNumber(methodNode), pattern, null,
|
||||||
SearchHints.create(searchMode).matchJavaSymbol());
|
Location.SearchHints.create(searchMode).matchJavaSymbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -582,7 +569,7 @@ public class ClassContext extends Context {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public Location getLocation(@NonNull AbstractInsnNode instruction) {
|
public Location getLocation(@NonNull AbstractInsnNode instruction) {
|
||||||
SearchHints hints = SearchHints.create(FORWARD).matchJavaSymbol();
|
Location.SearchHints hints = Location.SearchHints.create(Location.SearchDirection.FORWARD).matchJavaSymbol();
|
||||||
String pattern = null;
|
String pattern = null;
|
||||||
if (instruction instanceof MethodInsnNode) {
|
if (instruction instanceof MethodInsnNode) {
|
||||||
MethodInsnNode call = (MethodInsnNode) instruction;
|
MethodInsnNode call = (MethodInsnNode) instruction;
|
||||||
|
|||||||
@@ -14,19 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.DOT_GRADLE;
|
|
||||||
import static com.android.SdkConstants.DOT_JAVA;
|
|
||||||
import static com.android.SdkConstants.DOT_XML;
|
|
||||||
import static com.android.SdkConstants.SUPPRESS_ALL;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.client.api.Configuration;
|
import com.android.tools.klint.client.api.Configuration;
|
||||||
import com.android.tools.lint.client.api.LintClient;
|
import com.android.tools.klint.client.api.LintClient;
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
import com.android.tools.klint.client.api.LintDriver;
|
||||||
import com.android.tools.lint.client.api.SdkInfo;
|
import com.android.tools.klint.client.api.SdkInfo;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -34,6 +29,8 @@ import java.util.EnumSet;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context passed to the detectors during an analysis run. It provides
|
* Context passed to the detectors during an analysis run. It provides
|
||||||
* information about the file being analyzed, it allows shared properties (so
|
* information about the file being analyzed, it allows shared properties (so
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
import org.jetbrains.uast.UCallExpression;
|
||||||
|
import org.jetbrains.uast.UClass;
|
||||||
|
import org.jetbrains.uast.UElement;
|
||||||
|
import org.jetbrains.uast.UFunction;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
@@ -33,17 +35,7 @@ import org.w3c.dom.Document;
|
|||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
|
||||||
import lombok.ast.ClassDeclaration;
|
|
||||||
import lombok.ast.ConstructorInvocation;
|
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A detector is able to find a particular problem (or a set of related problems).
|
* A detector is able to find a particular problem (or a set of related problems).
|
||||||
@@ -70,192 +62,6 @@ import lombok.ast.Node;
|
|||||||
*/
|
*/
|
||||||
@Beta
|
@Beta
|
||||||
public abstract class Detector {
|
public abstract class Detector {
|
||||||
/** Specialized interface for detectors that scan Java source file parse trees */
|
|
||||||
public interface JavaScanner {
|
|
||||||
/**
|
|
||||||
* Create a parse tree visitor to process the parse tree. All
|
|
||||||
* {@link JavaScanner} detectors must provide a visitor, unless they
|
|
||||||
* either return true from {@link #appliesToResourceRefs()} or return
|
|
||||||
* non null from {@link #getApplicableMethodNames()}.
|
|
||||||
* <p>
|
|
||||||
* If you return specific AST node types from
|
|
||||||
* {@link #getApplicableNodeTypes()}, then the visitor will <b>only</b>
|
|
||||||
* be called for the specific requested node types. This is more
|
|
||||||
* efficient, since it allows many detectors that apply to only a small
|
|
||||||
* part of the AST (such as method call nodes) to share iteration of the
|
|
||||||
* majority of the parse tree.
|
|
||||||
* <p>
|
|
||||||
* If you return null from {@link #getApplicableNodeTypes()}, then your
|
|
||||||
* visitor will be called from the top and all node types visited.
|
|
||||||
* <p>
|
|
||||||
* Note that a new visitor is created for each separate compilation
|
|
||||||
* unit, so you can store per file state in the visitor.
|
|
||||||
*
|
|
||||||
* @param context the {@link Context} for the file being analyzed
|
|
||||||
* @return a visitor, or null.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
AstVisitor createJavaVisitor(@NonNull JavaContext context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the types of AST nodes that the visitor returned from
|
|
||||||
* {@link #createJavaVisitor(JavaContext)} should visit. See the
|
|
||||||
* documentation for {@link #createJavaVisitor(JavaContext)} for details
|
|
||||||
* on how the shared visitor is used.
|
|
||||||
* <p>
|
|
||||||
* If you return null from this method, then the visitor will process
|
|
||||||
* the full tree instead.
|
|
||||||
* <p>
|
|
||||||
* Note that for the shared visitor, the return codes from the visit
|
|
||||||
* methods are ignored: returning true will <b>not</b> prune iteration
|
|
||||||
* of the subtree, since there may be other node types interested in the
|
|
||||||
* children. If you need to ensure that your visitor only processes a
|
|
||||||
* part of the tree, use a full visitor instead. See the
|
|
||||||
* OverdrawDetector implementation for an example of this.
|
|
||||||
*
|
|
||||||
* @return the list of applicable node types (AST node classes), or null
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
List<Class<? extends Node>> getApplicableNodeTypes();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the list of method names this detector is interested in, or
|
|
||||||
* null. If this method returns non-null, then any AST nodes that match
|
|
||||||
* a method call in the list will be passed to the
|
|
||||||
* {@link #visitMethod(JavaContext, AstVisitor, MethodInvocation)}
|
|
||||||
* method for processing. The visitor created by
|
|
||||||
* {@link #createJavaVisitor(JavaContext)} is also passed to that
|
|
||||||
* method, although it can be null.
|
|
||||||
* <p>
|
|
||||||
* This makes it easy to write detectors that focus on some fixed calls.
|
|
||||||
* For example, the StringFormatDetector uses this mechanism to look for
|
|
||||||
* "format" calls, and when found it looks around (using the AST's
|
|
||||||
* {@link Node#getParent()} method) to see if it's called on
|
|
||||||
* a String class instance, and if so do its normal processing. Note
|
|
||||||
* that since it doesn't need to do any other AST processing, that
|
|
||||||
* detector does not actually supply a visitor.
|
|
||||||
*
|
|
||||||
* @return a set of applicable method names, or null.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
List<String> getApplicableMethodNames();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method invoked for any method calls found that matches any names
|
|
||||||
* returned by {@link #getApplicableMethodNames()}. This also passes
|
|
||||||
* back the visitor that was created by
|
|
||||||
* {@link #createJavaVisitor(JavaContext)}, but a visitor is not
|
|
||||||
* required. It is intended for detectors that need to do additional AST
|
|
||||||
* processing, but also want the convenience of not having to look for
|
|
||||||
* method names on their own.
|
|
||||||
*
|
|
||||||
* @param context the context of the lint request
|
|
||||||
* @param visitor the visitor created from
|
|
||||||
* {@link #createJavaVisitor(JavaContext)}, or null
|
|
||||||
* @param node the {@link MethodInvocation} node for the invoked method
|
|
||||||
*/
|
|
||||||
void visitMethod(
|
|
||||||
@NonNull JavaContext context,
|
|
||||||
@Nullable AstVisitor visitor,
|
|
||||||
@NonNull MethodInvocation node);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the list of constructor types this detector is interested in, or
|
|
||||||
* null. If this method returns non-null, then any AST nodes that match
|
|
||||||
* a constructor call in the list will be passed to the
|
|
||||||
* {@link #visitConstructor(JavaContext, AstVisitor, ConstructorInvocation, ResolvedMethod)}
|
|
||||||
* method for processing. The visitor created by
|
|
||||||
* {@link #createJavaVisitor(JavaContext)} is also passed to that
|
|
||||||
* method, although it can be null.
|
|
||||||
* <p>
|
|
||||||
* This makes it easy to write detectors that focus on some fixed constructors.
|
|
||||||
*
|
|
||||||
* @return a set of applicable fully qualified types, or null.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
List<String> getApplicableConstructorTypes();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method invoked for any constructor calls found that matches any names
|
|
||||||
* returned by {@link #getApplicableConstructorTypes()}. This also passes
|
|
||||||
* back the visitor that was created by
|
|
||||||
* {@link #createJavaVisitor(JavaContext)}, but a visitor is not
|
|
||||||
* required. It is intended for detectors that need to do additional AST
|
|
||||||
* processing, but also want the convenience of not having to look for
|
|
||||||
* method names on their own.
|
|
||||||
*
|
|
||||||
* @param context the context of the lint request
|
|
||||||
* @param visitor the visitor created from
|
|
||||||
* {@link #createJavaVisitor(JavaContext)}, or null
|
|
||||||
* @param node the {@link ConstructorInvocation} node for the invoked method
|
|
||||||
* @param constructor the resolved constructor method with type information
|
|
||||||
*/
|
|
||||||
void visitConstructor(
|
|
||||||
@NonNull JavaContext context,
|
|
||||||
@Nullable AstVisitor visitor,
|
|
||||||
@NonNull ConstructorInvocation node,
|
|
||||||
@NonNull ResolvedMethod constructor);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether this detector cares about Android resource references
|
|
||||||
* (such as {@code R.layout.main} or {@code R.string.app_name}). If it
|
|
||||||
* does, then the visitor will look for these patterns, and if found, it
|
|
||||||
* will invoke {@link #visitResourceReference} passing the resource type
|
|
||||||
* and resource name. It also passes the visitor, if any, that was
|
|
||||||
* created by {@link #createJavaVisitor(JavaContext)}, such that a
|
|
||||||
* detector can do more than just look for resources.
|
|
||||||
*
|
|
||||||
* @return true if this detector wants to be notified of R resource
|
|
||||||
* identifiers found in the code.
|
|
||||||
*/
|
|
||||||
boolean appliesToResourceRefs();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called for any resource references (such as {@code R.layout.main}
|
|
||||||
* found in Java code, provided this detector returned {@code true} from
|
|
||||||
* {@link #appliesToResourceRefs()}.
|
|
||||||
*
|
|
||||||
* @param context the lint scanning context
|
|
||||||
* @param visitor the visitor created from
|
|
||||||
* {@link #createJavaVisitor(JavaContext)}, or null
|
|
||||||
* @param node the variable reference for the resource
|
|
||||||
* @param type the resource type, such as "layout" or "string"
|
|
||||||
* @param name the resource name, such as "main" from
|
|
||||||
* {@code R.layout.main}
|
|
||||||
* @param isFramework whether the resource is a framework resource
|
|
||||||
* (android.R) or a local project resource (R)
|
|
||||||
*/
|
|
||||||
void visitResourceReference(
|
|
||||||
@NonNull JavaContext context,
|
|
||||||
@Nullable AstVisitor visitor,
|
|
||||||
@NonNull Node node,
|
|
||||||
@NonNull String type,
|
|
||||||
@NonNull String name,
|
|
||||||
boolean isFramework);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of fully qualified names for super classes that this
|
|
||||||
* detector cares about. If not null, this detector will *only* be called
|
|
||||||
* if the current class is a subclass of one of the specified superclasses.
|
|
||||||
*
|
|
||||||
* @return a list of fully qualified names
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
List<String> applicableSuperClasses();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called for each class that extends one of the super classes specified with
|
|
||||||
* {@link #applicableSuperClasses()}
|
|
||||||
*
|
|
||||||
* @param context the lint scanning context
|
|
||||||
* @param declaration the class declaration node, or null for anonymous classes
|
|
||||||
* @param node the class declaration node or the anonymous class construction node
|
|
||||||
* @param resolvedClass the resolved class
|
|
||||||
*/
|
|
||||||
void checkClass(@NonNull JavaContext context, @Nullable ClassDeclaration declaration,
|
|
||||||
@NonNull Node node, @NonNull ResolvedClass resolvedClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Specialized interface for detectors that scan Java class files */
|
/** Specialized interface for detectors that scan Java class files */
|
||||||
public interface ClassScanner {
|
public interface ClassScanner {
|
||||||
/**
|
/**
|
||||||
@@ -664,52 +470,48 @@ public abstract class Detector {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable @SuppressWarnings("javadoc")
|
|
||||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @SuppressWarnings("javadoc")
|
|
||||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("javadoc")
|
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
|
||||||
@NonNull MethodInvocation node) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("javadoc")
|
@SuppressWarnings("javadoc")
|
||||||
public boolean appliesToResourceRefs() {
|
public boolean appliesToResourceRefs() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("javadoc")
|
@SuppressWarnings("javadoc")
|
||||||
public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitResourceReference(
|
||||||
@NonNull Node node, @NonNull String type, @NonNull String name,
|
UastAndroidContext context,
|
||||||
boolean isFramework) {
|
UElement element,
|
||||||
}
|
String type,
|
||||||
|
String name,
|
||||||
@Nullable
|
boolean isFramework
|
||||||
public List<String> applicableSuperClasses() {
|
) {}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkClass(@NonNull JavaContext context, @Nullable ClassDeclaration declaration,
|
|
||||||
@NonNull Node node, @NonNull ResolvedClass resolvedClass) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @SuppressWarnings("javadoc")
|
@Nullable @SuppressWarnings("javadoc")
|
||||||
public List<String> getApplicableConstructorTypes() {
|
public List<String> getApplicableConstructorTypes() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("javadoc")
|
public List<String> getApplicableSuperClasses() {
|
||||||
public void visitConstructor(
|
return null;
|
||||||
@NonNull JavaContext context,
|
}
|
||||||
@Nullable AstVisitor visitor,
|
|
||||||
@NonNull ConstructorInvocation node,
|
public void visitClass(UastAndroidContext context, UClass node) {
|
||||||
@NonNull ResolvedMethod constructor) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getApplicableFunctionNames() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitConstructor(UastAndroidContext context, UCallExpression functionCall,
|
||||||
|
UFunction constructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public UastVisitor createUastVisitor(UastAndroidContext context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Dummy implementations to make implementing a ClassScanner easier: ----
|
// ---- Dummy implementations to make implementing a ClassScanner easier: ----
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|||||||
@@ -14,12 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import static com.android.tools.lint.detector.api.TextFormat.RAW;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.client.api.Configuration;
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -142,7 +139,7 @@ public final class Issue implements Comparable<Issue> {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getBriefDescription(@NonNull TextFormat format) {
|
public String getBriefDescription(@NonNull TextFormat format) {
|
||||||
return RAW.convertTo(mBriefDescription, format);
|
return TextFormat.RAW.convertTo(mBriefDescription, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,7 +153,7 @@ public final class Issue implements Comparable<Issue> {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getExplanation(@NonNull TextFormat format) {
|
public String getExplanation(@NonNull TextFormat format) {
|
||||||
return RAW.convertTo(mExplanation, format);
|
return TextFormat.RAW.convertTo(mExplanation, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,28 +14,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CLASS_CONTEXT;
|
|
||||||
import static com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
|
||||||
import static com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.client.api.JavaParser;
|
import com.android.tools.klint.client.api.LintDriver;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
import org.jetbrains.uast.*;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Iterator;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.ClassDeclaration;
|
import static com.android.SdkConstants.CLASS_CONTEXT;
|
||||||
import lombok.ast.ConstructorDeclaration;
|
|
||||||
import lombok.ast.Expression;
|
|
||||||
import lombok.ast.MethodDeclaration;
|
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
import lombok.ast.Position;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Context} used when checking Java files.
|
* A {@link Context} used when checking Java files.
|
||||||
@@ -43,14 +34,11 @@ import lombok.ast.Position;
|
|||||||
* <b>NOTE: This is not a public or final API; if you rely on this be prepared
|
* <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>
|
* to adjust your code for the next tools release.</b>
|
||||||
*/
|
*/
|
||||||
public class JavaContext extends Context {
|
public class JavaContext extends Context implements UastAndroidContext {
|
||||||
static final String SUPPRESS_COMMENT_PREFIX = "//noinspection "; //$NON-NLS-1$
|
static final String SUPPRESS_COMMENT_PREFIX = "//noinspection "; //$NON-NLS-1$
|
||||||
|
|
||||||
/** The parse tree */
|
/** The parse tree */
|
||||||
private Node mCompilationUnit;
|
private UFile mCompilationUnit;
|
||||||
|
|
||||||
/** The parser which produced the parse tree */
|
|
||||||
private final JavaParser mParser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@link JavaContext} for running lint on the given file, with
|
* Constructs a {@link JavaContext} for running lint on the given file, with
|
||||||
@@ -70,10 +58,8 @@ public class JavaContext extends Context {
|
|||||||
@NonNull LintDriver driver,
|
@NonNull LintDriver driver,
|
||||||
@NonNull Project project,
|
@NonNull Project project,
|
||||||
@Nullable Project main,
|
@Nullable Project main,
|
||||||
@NonNull File file,
|
@NonNull File file) {
|
||||||
@NonNull JavaParser parser) {
|
|
||||||
super(driver, project, main, file);
|
super(driver, project, main, file);
|
||||||
mParser = parser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,18 +68,13 @@ public class JavaContext extends Context {
|
|||||||
* @param node the AST node to get a location for
|
* @param node the AST node to get a location for
|
||||||
* @return a location for the given node
|
* @return a location for the given node
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@Override
|
||||||
public Location getLocation(@NonNull Node node) {
|
public Location getLocation(@NotNull UElement element) {
|
||||||
return mParser.getLocation(this, node);
|
return UastAndroidContext.DefaultImpls.getLocation(this, element);
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public JavaParser getParser() {
|
|
||||||
return mParser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Node getCompilationUnit() {
|
public UFile getCompilationUnit() {
|
||||||
return mCompilationUnit;
|
return mCompilationUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +84,7 @@ public class JavaContext extends Context {
|
|||||||
*
|
*
|
||||||
* @param compilationUnit the parse tree
|
* @param compilationUnit the parse tree
|
||||||
*/
|
*/
|
||||||
public void setCompilationUnit(@Nullable Node compilationUnit) {
|
public void setCompilationUnit(@Nullable UFile compilationUnit) {
|
||||||
mCompilationUnit = compilationUnit;
|
mCompilationUnit = compilationUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,107 +108,24 @@ public class JavaContext extends Context {
|
|||||||
* @param location the location of the issue, or null if not known
|
* @param location the location of the issue, or null if not known
|
||||||
* @param message the message for this warning
|
* @param message the message for this warning
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void report(
|
public void report(
|
||||||
@NonNull Issue issue,
|
@NonNull Issue issue,
|
||||||
@Nullable Node scope,
|
@Nullable UElement scope,
|
||||||
@Nullable Location location,
|
@Nullable Location location,
|
||||||
@NonNull String message) {
|
@NonNull String message) {
|
||||||
if (scope != null && mDriver.isSuppressed(this, issue, scope)) {
|
if (scope != null && mDriver.isSuppressed(this, issue, scope)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
super.report(issue, location, message);
|
super.report(issue, location, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Report an error.
|
|
||||||
* Like {@link #report(Issue, Node, Location, String)} but with
|
|
||||||
* a now-unused data parameter at the end.
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #report(Issue, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static Node findSurroundingMethod(Node scope) {
|
|
||||||
while (scope != null) {
|
|
||||||
Class<? extends Node> type = scope.getClass();
|
|
||||||
// The Lombok AST uses a flat hierarchy of node type implementation classes
|
|
||||||
// so no need to do instanceof stuff here.
|
|
||||||
if (type == MethodDeclaration.class || type == ConstructorDeclaration.class) {
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
scope = scope.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static ClassDeclaration findSurroundingClass(@Nullable Node scope) {
|
|
||||||
while (scope != null) {
|
|
||||||
Class<? extends Node> type = scope.getClass();
|
|
||||||
// The Lombok AST uses a flat hierarchy of node type implementation classes
|
|
||||||
// so no need to do instanceof stuff here.
|
|
||||||
if (type == ClassDeclaration.class) {
|
|
||||||
return (ClassDeclaration) scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
scope = scope.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
protected String getSuppressCommentPrefix() {
|
protected String getSuppressCommentPrefix() {
|
||||||
return SUPPRESS_COMMENT_PREFIX;
|
return SUPPRESS_COMMENT_PREFIX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSuppressedWithComment(@NonNull Node scope, @NonNull Issue issue) {
|
|
||||||
// Check whether there is a comment marker
|
|
||||||
String contents = getContents();
|
|
||||||
assert contents != null; // otherwise we wouldn't be here
|
|
||||||
Position position = scope.getPosition();
|
|
||||||
if (position == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int start = position.getStart();
|
|
||||||
return isSuppressedWithComment(start, issue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public Location.Handle createLocationHandle(@NonNull Node node) {
|
|
||||||
return mParser.createLocationHandle(this, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ResolvedNode resolve(@NonNull Node node) {
|
|
||||||
return mParser.resolve(this, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ResolvedClass findClass(@NonNull String fullyQualifiedName) {
|
|
||||||
return mParser.findClass(this, fullyQualifiedName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public TypeDescriptor getType(@NonNull Node node) {
|
|
||||||
return mParser.getType(this, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given method invocation node corresponds to a call on a
|
* Returns true if the given method invocation node corresponds to a call on a
|
||||||
* {@code android.content.Context}
|
* {@code android.content.Context}
|
||||||
@@ -235,160 +133,35 @@ public class JavaContext extends Context {
|
|||||||
* @param node the method call node
|
* @param node the method call node
|
||||||
* @return true iff the method call is on a class extending context
|
* @return true iff the method call is on a class extending context
|
||||||
*/
|
*/
|
||||||
public boolean isContextMethod(@NonNull MethodInvocation node) {
|
public boolean isContextMethod(@NonNull UCallExpression node) {
|
||||||
// Method name used in many other contexts where it doesn't have the
|
// Method name used in many other contexts where it doesn't have the
|
||||||
// same semantics; only use this one if we can resolve types
|
// same semantics; only use this one if we can resolve types
|
||||||
// and we're certain this is the Context method
|
// and we're certain this is the Context method
|
||||||
ResolvedNode resolved = resolve(node);
|
UFunction resolved = node.resolve(this);
|
||||||
if (resolved instanceof JavaParser.ResolvedMethod) {
|
UClass containingClass = UastUtils.getContainingClass(resolved);
|
||||||
JavaParser.ResolvedMethod method = (JavaParser.ResolvedMethod) resolved;
|
if (resolved != null && containingClass != null) {
|
||||||
ResolvedClass containingClass = method.getContainingClass();
|
if (containingClass.isSubclassOf(CLASS_CONTEXT)) {
|
||||||
if (containingClass.isSubclassOf(CLASS_CONTEXT, false)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@NotNull
|
||||||
* Returns the first ancestor node of the given type
|
@Override
|
||||||
*
|
public JavaContext getLintContext() {
|
||||||
* @param element the element to search from
|
return this;
|
||||||
* @param clz the target node type
|
|
||||||
* @param <T> the target node type
|
|
||||||
* @return the nearest ancestor node in the parent chain, or null if not found
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static <T extends Node> T getParentOfType(
|
|
||||||
@Nullable Node element,
|
|
||||||
@NonNull Class<T> clz) {
|
|
||||||
return getParentOfType(element, clz, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@NotNull
|
||||||
* Returns the first ancestor node of the given type
|
@Override
|
||||||
*
|
public List<UastConverter> getConverters() {
|
||||||
* @param element the element to search from
|
return getClient().getConverters();
|
||||||
* @param clz the target node type
|
|
||||||
* @param strict if true, do not consider the element itself, only its parents
|
|
||||||
* @param <T> the target node type
|
|
||||||
* @return the nearest ancestor node in the parent chain, or null if not found
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static <T extends Node> T getParentOfType(
|
|
||||||
@Nullable Node element,
|
|
||||||
@NonNull Class<T> clz,
|
|
||||||
boolean strict) {
|
|
||||||
if (element == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strict) {
|
|
||||||
element = element.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (element != null) {
|
|
||||||
if (clz.isInstance(element)) {
|
|
||||||
//noinspection unchecked
|
|
||||||
return (T) element;
|
|
||||||
}
|
|
||||||
element = element.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@org.jetbrains.annotations.Nullable
|
||||||
* Returns the first ancestor node of the given type, stopping at the given type
|
@Override
|
||||||
*
|
public UElement convert(@Nullable Object element) {
|
||||||
* @param element the element to search from
|
return UastContext.DefaultImpls.convert(this, element);
|
||||||
* @param clz the target node type
|
|
||||||
* @param strict if true, do not consider the element itself, only its parents
|
|
||||||
* @param terminators optional node types to terminate the search at
|
|
||||||
* @param <T> the target node type
|
|
||||||
* @return the nearest ancestor node in the parent chain, or null if not found
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static <T extends Node> T getParentOfType(@Nullable Node element,
|
|
||||||
@NonNull Class<T> clz,
|
|
||||||
boolean strict,
|
|
||||||
@NonNull Class<? extends Node>... terminators) {
|
|
||||||
if (element == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (strict) {
|
|
||||||
element = element.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (element != null && !clz.isInstance(element)) {
|
|
||||||
for (Class<?> terminator : terminators) {
|
|
||||||
if (terminator.isInstance(element)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
element = element.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
//noinspection unchecked
|
|
||||||
return (T) element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first sibling of the given node that is of the given class
|
|
||||||
*
|
|
||||||
* @param sibling the sibling to search from
|
|
||||||
* @param clz the type to look for
|
|
||||||
* @param <T> the type
|
|
||||||
* @return the first sibling of the given type, or null
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static <T extends Node> T getNextSiblingOfType(@Nullable Node sibling,
|
|
||||||
@NonNull Class<T> clz) {
|
|
||||||
if (sibling == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Node parent = sibling.getParent();
|
|
||||||
if (parent == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<Node> iterator = parent.getChildren().iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
if (iterator.next() == sibling) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Node child = iterator.next();
|
|
||||||
if (clz.isInstance(child)) {
|
|
||||||
//noinspection unchecked
|
|
||||||
return (T) child;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the given argument of the given call
|
|
||||||
*
|
|
||||||
* @param call the call containing arguments
|
|
||||||
* @param index the index of the target argument
|
|
||||||
* @return the argument at the given index
|
|
||||||
* @throws IllegalArgumentException if index is outside the valid range
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public static Node getArgumentNode(@NonNull MethodInvocation call, int index) {
|
|
||||||
int i = 0;
|
|
||||||
for (Expression parameter : call.astArguments()) {
|
|
||||||
if (i == index) {
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException(Integer.toString(index));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,25 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
|
||||||
import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
|
|
||||||
import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
|
|
||||||
import static com.android.SdkConstants.ATTR_PADDING;
|
|
||||||
import static com.android.SdkConstants.ATTR_PADDING_BOTTOM;
|
|
||||||
import static com.android.SdkConstants.ATTR_PADDING_LEFT;
|
|
||||||
import static com.android.SdkConstants.ATTR_PADDING_RIGHT;
|
|
||||||
import static com.android.SdkConstants.ATTR_PADDING_TOP;
|
|
||||||
import static com.android.SdkConstants.VALUE_FILL_PARENT;
|
|
||||||
import static com.android.SdkConstants.VALUE_MATCH_PARENT;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class specifically intended for layout detectors which provides some
|
* Abstract class specifically intended for layout detectors which provides some
|
||||||
* common utility methods shared by layout detectors.
|
* common utility methods shared by layout detectors.
|
||||||
|
|||||||
@@ -14,25 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
|
|
||||||
import static com.android.SdkConstants.ANDROID_PREFIX;
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
|
||||||
import static com.android.SdkConstants.ATTR_LOCALE;
|
|
||||||
import static com.android.SdkConstants.BIN_FOLDER;
|
|
||||||
import static com.android.SdkConstants.DOT_GIF;
|
|
||||||
import static com.android.SdkConstants.DOT_JPEG;
|
|
||||||
import static com.android.SdkConstants.DOT_JPG;
|
|
||||||
import static com.android.SdkConstants.DOT_PNG;
|
|
||||||
import static com.android.SdkConstants.DOT_WEBP;
|
|
||||||
import static com.android.SdkConstants.DOT_XML;
|
|
||||||
import static com.android.SdkConstants.ID_PREFIX;
|
|
||||||
import static com.android.SdkConstants.NEW_ID_PREFIX;
|
|
||||||
import static com.android.SdkConstants.TOOLS_URI;
|
|
||||||
import static com.android.SdkConstants.UTF_8;
|
|
||||||
import static com.android.ide.common.resources.configuration.FolderConfiguration.QUALIFIER_SPLITTER;
|
|
||||||
import static com.android.ide.common.resources.configuration.LocaleQualifier.BCP_47_PREFIX;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
@@ -53,7 +35,7 @@ import com.android.sdklib.AndroidVersion;
|
|||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkVersionInfo;
|
import com.android.sdklib.SdkVersionInfo;
|
||||||
import com.android.sdklib.repository.FullRevision;
|
import com.android.sdklib.repository.FullRevision;
|
||||||
import com.android.tools.lint.client.api.LintClient;
|
import com.android.tools.klint.client.api.LintClient;
|
||||||
import com.android.utils.PositionXmlParser;
|
import com.android.utils.PositionXmlParser;
|
||||||
import com.android.utils.SdkUtils;
|
import com.android.utils.SdkUtils;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
@@ -61,7 +43,8 @@ import com.google.common.base.Splitter;
|
|||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import org.jetbrains.uast.UFile;
|
||||||
|
import org.jetbrains.uast.UImportStatement;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
@@ -74,19 +57,14 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayDeque;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.regex.PatternSyntaxException;
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
import lombok.ast.ImportDeclaration;
|
import static com.android.SdkConstants.*;
|
||||||
|
import static com.android.ide.common.resources.configuration.FolderConfiguration.QUALIFIER_SPLITTER;
|
||||||
|
import static com.android.ide.common.resources.configuration.LocaleQualifier.BCP_47_PREFIX;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Useful utility methods related to lint.
|
* Useful utility methods related to lint.
|
||||||
@@ -796,7 +774,7 @@ public class LintUtils {
|
|||||||
* qualified name
|
* qualified name
|
||||||
*/
|
*/
|
||||||
public static boolean isImported(
|
public static boolean isImported(
|
||||||
@Nullable lombok.ast.Node compilationUnit,
|
@Nullable UFile compilationUnit,
|
||||||
@NonNull String fullyQualifiedName) {
|
@NonNull String fullyQualifiedName) {
|
||||||
if (compilationUnit == null) {
|
if (compilationUnit == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -805,26 +783,27 @@ public class LintUtils {
|
|||||||
int dotLength = fullyQualifiedName.length() - dotIndex;
|
int dotLength = fullyQualifiedName.length() - dotIndex;
|
||||||
|
|
||||||
boolean imported = false;
|
boolean imported = false;
|
||||||
for (lombok.ast.Node rootNode : compilationUnit.getChildren()) {
|
for (UImportStatement importStatement : compilationUnit.getImportStatements()) {
|
||||||
if (rootNode instanceof ImportDeclaration) {
|
String fqn = importStatement.getNameToImport();
|
||||||
ImportDeclaration importDeclaration = (ImportDeclaration) rootNode;
|
if (fqn == null) {
|
||||||
String fqn = importDeclaration.asFullyQualifiedName();
|
continue;
|
||||||
if (fqn.equals(fullyQualifiedName)) {
|
}
|
||||||
return true;
|
|
||||||
} else if (fullyQualifiedName.regionMatches(dotIndex, fqn,
|
if (fqn.equals(fullyQualifiedName)) {
|
||||||
fqn.length() - dotLength, dotLength)) {
|
return true;
|
||||||
// This import is importing the class name using some other prefix, so there
|
} else if (fullyQualifiedName.regionMatches(dotIndex, fqn,
|
||||||
// fully qualified class name cannot be imported under that name
|
fqn.length() - dotLength, dotLength)) {
|
||||||
return false;
|
// This import is importing the class name using some other prefix, so there
|
||||||
} else if (importDeclaration.astStarImport()
|
// fully qualified class name cannot be imported under that name
|
||||||
&& fqn.regionMatches(0, fqn, 0, dotIndex + 1)) {
|
return false;
|
||||||
imported = true;
|
} else if (importStatement.isStarImport()
|
||||||
// but don't break -- keep searching in case there's a non-wildcard
|
&& fqn.regionMatches(0, fqn, 0, dotIndex + 1)) {
|
||||||
// import of the specific class name, e.g. if we're looking for
|
imported = true;
|
||||||
// android.content.SharedPreferences.Editor, don't match on the following:
|
// but don't break -- keep searching in case there's a non-wildcard
|
||||||
// import android.content.SharedPreferences.*;
|
// import of the specific class name, e.g. if we're looking for
|
||||||
// import foo.bar.Editor;
|
// android.content.SharedPreferences.Editor, don't match on the following:
|
||||||
}
|
// import android.content.SharedPreferences.*;
|
||||||
|
// import foo.bar.Editor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.SdkConstants;
|
import com.android.SdkConstants;
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
@@ -28,10 +28,10 @@ import com.android.resources.ResourceFolderType;
|
|||||||
import com.android.sdklib.AndroidVersion;
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkVersionInfo;
|
import com.android.sdklib.SdkVersionInfo;
|
||||||
import com.android.tools.lint.client.api.CircularDependencyException;
|
import com.android.tools.klint.client.api.CircularDependencyException;
|
||||||
import com.android.tools.lint.client.api.Configuration;
|
import com.android.tools.klint.client.api.Configuration;
|
||||||
import com.android.tools.lint.client.api.LintClient;
|
import com.android.tools.klint.client.api.LintClient;
|
||||||
import com.android.tools.lint.client.api.SdkInfo;
|
import com.android.tools.klint.client.api.SdkInfo;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
import com.google.common.base.CharMatcher;
|
import com.google.common.base.CharMatcher;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
|
|||||||
@@ -14,12 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
import com.android.tools.klint.client.api.LintDriver;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
|
|||||||
@@ -14,27 +14,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
|
|
||||||
import static com.android.SdkConstants.DOT_CLASS;
|
|
||||||
import static com.android.SdkConstants.DOT_GRADLE;
|
|
||||||
import static com.android.SdkConstants.DOT_JAVA;
|
|
||||||
import static com.android.SdkConstants.DOT_PNG;
|
|
||||||
import static com.android.SdkConstants.DOT_PROPERTIES;
|
|
||||||
import static com.android.SdkConstants.DOT_XML;
|
|
||||||
import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE;
|
|
||||||
import static com.android.SdkConstants.OLD_PROGUARD_FILE;
|
|
||||||
import static com.android.SdkConstants.RES_FOLDER;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
import org.jetbrains.uast.UastConverterUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The scope of a detector is the set of files a detector must consider when
|
* The scope of a detector is the set of files a detector must consider when
|
||||||
* performing its analysis. This can be used to determine when issues are
|
* performing its analysis. This can be used to determine when issues are
|
||||||
@@ -80,14 +72,14 @@ public enum Scope {
|
|||||||
* Issues which are only affected by a single Java source file can be
|
* Issues which are only affected by a single Java source file can be
|
||||||
* checked for incrementally when a Java source file is edited.
|
* checked for incrementally when a Java source file is edited.
|
||||||
*/
|
*/
|
||||||
JAVA_FILE,
|
SOURCE_FILE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The analysis considers <b>all</b> the Java source files together.
|
* The analysis considers <b>all</b> the Java source files together.
|
||||||
* <p>
|
* <p>
|
||||||
* This flag is mutually exclusive with {@link #JAVA_FILE}.
|
* This flag is mutually exclusive with {@link #SOURCE_FILE}.
|
||||||
*/
|
*/
|
||||||
ALL_JAVA_FILES,
|
ALL_SOURCE_FILES,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The analysis only considers a single Java class file at a time.
|
* The analysis only considers a single Java class file at a time.
|
||||||
@@ -143,10 +135,10 @@ public enum Scope {
|
|||||||
if (size == 2) {
|
if (size == 2) {
|
||||||
// When single checking a Java source file, we check both its Java source
|
// When single checking a Java source file, we check both its Java source
|
||||||
// and the associated class files
|
// and the associated class files
|
||||||
return scopes.contains(JAVA_FILE) && scopes.contains(CLASS_FILE);
|
return scopes.contains(SOURCE_FILE) && scopes.contains(CLASS_FILE);
|
||||||
} else {
|
} else {
|
||||||
return size == 1 &&
|
return size == 1 &&
|
||||||
(scopes.contains(JAVA_FILE)
|
(scopes.contains(SOURCE_FILE)
|
||||||
|| scopes.contains(CLASS_FILE)
|
|| scopes.contains(CLASS_FILE)
|
||||||
|| scopes.contains(RESOURCE_FILE)
|
|| scopes.contains(RESOURCE_FILE)
|
||||||
|| scopes.contains(PROGUARD_FILE)
|
|| scopes.contains(PROGUARD_FILE)
|
||||||
@@ -192,7 +184,7 @@ public enum Scope {
|
|||||||
} else if (name.endsWith(DOT_XML)) {
|
} else if (name.endsWith(DOT_XML)) {
|
||||||
scope.add(RESOURCE_FILE);
|
scope.add(RESOURCE_FILE);
|
||||||
} else if (name.endsWith(DOT_JAVA)) {
|
} else if (name.endsWith(DOT_JAVA)) {
|
||||||
scope.add(JAVA_FILE);
|
scope.add(SOURCE_FILE);
|
||||||
} else if (name.endsWith(DOT_CLASS)) {
|
} else if (name.endsWith(DOT_CLASS)) {
|
||||||
scope.add(CLASS_FILE);
|
scope.add(CLASS_FILE);
|
||||||
} else if (name.endsWith(DOT_GRADLE)) {
|
} else if (name.endsWith(DOT_GRADLE)) {
|
||||||
@@ -210,6 +202,9 @@ public enum Scope {
|
|||||||
scope.add(RESOURCE_FILE);
|
scope.add(RESOURCE_FILE);
|
||||||
scope.add(BINARY_RESOURCE_FILE);
|
scope.add(BINARY_RESOURCE_FILE);
|
||||||
scope.add(RESOURCE_FOLDER);
|
scope.add(RESOURCE_FOLDER);
|
||||||
|
} else if (UastConverterUtils.isFileSupported(
|
||||||
|
project.getClient().getConverters(), name)) {
|
||||||
|
scope.add(SOURCE_FILE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -231,7 +226,7 @@ public enum Scope {
|
|||||||
/** Scope-set used for detectors which scan all resources */
|
/** Scope-set used for detectors which scan all resources */
|
||||||
public static final EnumSet<Scope> ALL_RESOURCES_SCOPE = EnumSet.of(ALL_RESOURCE_FILES);
|
public static final EnumSet<Scope> ALL_RESOURCES_SCOPE = EnumSet.of(ALL_RESOURCE_FILES);
|
||||||
/** Scope-set used for detectors which are affected by a single Java source file */
|
/** Scope-set used for detectors which are affected by a single Java source file */
|
||||||
public static final EnumSet<Scope> JAVA_FILE_SCOPE = EnumSet.of(JAVA_FILE);
|
public static final EnumSet<Scope> JAVA_FILE_SCOPE = EnumSet.of(SOURCE_FILE);
|
||||||
/** Scope-set used for detectors which are affected by a single Java class file */
|
/** Scope-set used for detectors which are affected by a single Java class file */
|
||||||
public static final EnumSet<Scope> CLASS_FILE_SCOPE = EnumSet.of(CLASS_FILE);
|
public static final EnumSet<Scope> CLASS_FILE_SCOPE = EnumSet.of(CLASS_FILE);
|
||||||
/** Scope-set used for detectors which are affected by a single Gradle build file */
|
/** Scope-set used for detectors which are affected by a single Gradle build file */
|
||||||
@@ -248,8 +243,8 @@ public enum Scope {
|
|||||||
public static final EnumSet<Scope> MANIFEST_AND_RESOURCE_SCOPE =
|
public static final EnumSet<Scope> MANIFEST_AND_RESOURCE_SCOPE =
|
||||||
EnumSet.of(Scope.MANIFEST, Scope.RESOURCE_FILE);
|
EnumSet.of(Scope.MANIFEST, Scope.RESOURCE_FILE);
|
||||||
/** Scope-set used for detectors which are affected by single XML and Java source files */
|
/** Scope-set used for detectors which are affected by single XML and Java source files */
|
||||||
public static final EnumSet<Scope> JAVA_AND_RESOURCE_FILES =
|
public static final EnumSet<Scope> SOURCE_AND_RESOURCE_FILES =
|
||||||
EnumSet.of(RESOURCE_FILE, JAVA_FILE);
|
EnumSet.of(RESOURCE_FILE, SOURCE_FILE);
|
||||||
/** Scope-set used for analyzing individual class files and all resource files */
|
/** Scope-set used for analyzing individual class files and all resource files */
|
||||||
public static final EnumSet<Scope> CLASS_AND_ALL_RESOURCE_FILES =
|
public static final EnumSet<Scope> CLASS_AND_ALL_RESOURCE_FILES =
|
||||||
EnumSet.of(ALL_RESOURCE_FILES, CLASS_FILE);
|
EnumSet.of(ALL_RESOURCE_FILES, CLASS_FILE);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.utils.SdkUtils;
|
import com.android.utils.SdkUtils;
|
||||||
|
|||||||
@@ -14,15 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.detector.api;
|
package com.android.tools.klint.detector.api;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
import com.android.tools.klint.client.api.LintDriver;
|
||||||
import com.android.tools.lint.client.api.XmlParser;
|
import com.android.tools.klint.client.api.XmlParser;
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="module" module-name="android-annotations" />
|
||||||
|
<orderEntry type="module" module-name="lint-api" />
|
||||||
|
<orderEntry type="library" name="android-plugin" level="project" />
|
||||||
|
<orderEntry type="library" name="guava" level="project" />
|
||||||
|
<orderEntry type="module" module-name="uast-android" />
|
||||||
|
<orderEntry type="library" name="intellij-core" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+9
-9
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
import static com.android.SdkConstants.ATTR_CONTENT_DESCRIPTION;
|
import static com.android.SdkConstants.ATTR_CONTENT_DESCRIPTION;
|
||||||
@@ -26,14 +26,14 @@ import static com.android.SdkConstants.VALUE_NO;
|
|||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|||||||
+28
-34
@@ -14,35 +14,34 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
|
|
||||||
import static com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import static com.android.tools.klint.client.api.JavaParser.TYPE_OBJECT;
|
||||||
import static com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
import static com.android.tools.klint.client.api.JavaParser.TYPE_STRING;
|
||||||
import static com.android.tools.lint.client.api.JavaParser.TYPE_OBJECT;
|
|
||||||
import static com.android.tools.lint.client.api.JavaParser.TYPE_STRING;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
|
||||||
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.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.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import lombok.ast.MethodInvocation;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
|
import org.jetbrains.uast.*;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that addJavascriptInterface is not called for API levels below 17.
|
* Ensures that addJavascriptInterface is not called for API levels below 17.
|
||||||
*/
|
*/
|
||||||
public class AddJavascriptInterfaceDetector extends Detector implements Detector.JavaScanner {
|
public class AddJavascriptInterfaceDetector extends Detector implements UastScanner {
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"AddJavascriptInterface", //$NON-NLS-1$
|
"AddJavascriptInterface", //$NON-NLS-1$
|
||||||
"addJavascriptInterface Called",
|
"addJavascriptInterface Called",
|
||||||
@@ -62,45 +61,40 @@ public class AddJavascriptInterfaceDetector extends Detector implements Detector
|
|||||||
private static final String WEB_VIEW = "android.webkit.WebView"; //$NON-NLS-1$
|
private static final String WEB_VIEW = "android.webkit.WebView"; //$NON-NLS-1$
|
||||||
private static final String ADD_JAVASCRIPT_INTERFACE = "addJavascriptInterface"; //$NON-NLS-1$
|
private static final String ADD_JAVASCRIPT_INTERFACE = "addJavascriptInterface"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Speed getSpeed() {
|
public Speed getSpeed() {
|
||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public List<String> getApplicableMethodNames() {
|
public List<String> getApplicableFunctionNames() {
|
||||||
return Collections.singletonList(ADD_JAVASCRIPT_INTERFACE);
|
return Collections.singletonList(ADD_JAVASCRIPT_INTERFACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation node) {
|
if (context.getLintContext().getMainProject().getMinSdk() >= 17) {
|
||||||
// Ignore the issue if we never build for any API less than 17.
|
|
||||||
if (context.getMainProject().getMinSdk() >= 17) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore if the method doesn't fit our description.
|
UFunction resolvedFunction = node.resolveOrEmpty(context);
|
||||||
ResolvedNode resolved = context.resolve(node);
|
UClass containingClass = UastUtils.getContainingClassOrEmpty(resolvedFunction);
|
||||||
if (!(resolved instanceof ResolvedMethod)) {
|
if (!containingClass.isSubclassOf(WEB_VIEW)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
List<UVariable> valueParameters = resolvedFunction.getValueParameters();
|
||||||
if (!method.getContainingClass().isSubclassOf(WEB_VIEW, false)) {
|
if (node.getValueArgumentCount() != 2
|
||||||
return;
|
|| !valueParameters.get(0).getType().matchesFqName(TYPE_OBJECT)
|
||||||
}
|
|| !valueParameters.get(1).getType().matchesFqName(TYPE_STRING)) {
|
||||||
if (method.getArgumentCount() != 2
|
|
||||||
|| !method.getArgumentType(0).matchesName(TYPE_OBJECT)
|
|
||||||
|| !method.getArgumentType(1).matchesName(TYPE_STRING)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String message = "`WebView.addJavascriptInterface` should not be called with minSdkVersion < 17 for security reasons: " +
|
String message = "`WebView.addJavascriptInterface` should not be called with minSdkVersion < 17 for security reasons: " +
|
||||||
"JavaScript can use reflection to manipulate application";
|
"JavaScript can use reflection to manipulate application";
|
||||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
context.report(ISSUE, node, UastAndroidUtils.getLocation(node), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,36 +14,30 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.ConstantEvaluator;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
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.io.File;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.Expression;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.MethodInvocation;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure that alarms are handled correctly
|
* Makes sure that alarms are handled correctly
|
||||||
*/
|
*/
|
||||||
public class AlarmDetector extends Detector implements Detector.JavaScanner {
|
public class AlarmDetector extends Detector implements UastScanner {
|
||||||
|
|
||||||
private static final Implementation IMPLEMENTATION = new Implementation(
|
private static final Implementation IMPLEMENTATION = new Implementation(
|
||||||
AlarmDetector.class,
|
AlarmDetector.class,
|
||||||
@@ -82,51 +76,38 @@ public class AlarmDetector extends Detector implements Detector.JavaScanner {
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getApplicableMethodNames() {
|
public List<String> getApplicableFunctionNames() {
|
||||||
return Collections.singletonList("setRepeating");
|
return Collections.singletonList("setRepeating");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation node) {
|
UFunction setRepeatingFunction = node.resolve(context);
|
||||||
ResolvedNode resolved = context.resolve(node);
|
UClass containingClass = UastUtils.getContainingClassOrEmpty(setRepeatingFunction);
|
||||||
if (resolved instanceof ResolvedMethod) {
|
|
||||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
if (containingClass.matchesFqName("android.app.AlarmManager")
|
||||||
if (method.getContainingClass().matches("android.app.AlarmManager")
|
&& node.getValueArgumentCount() == 4) {
|
||||||
&& method.getArgumentCount() == 4) {
|
ensureAtLeast(context, node, 1, 5000L);
|
||||||
ensureAtLeast(context, node, 1, 5000L);
|
ensureAtLeast(context, node, 2, 60000L);
|
||||||
ensureAtLeast(context, node, 2, 60000L);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureAtLeast(@NonNull JavaContext context,
|
private static void ensureAtLeast(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation node, int parameter, long min) {
|
@NonNull UCallExpression node, int parameter, long min) {
|
||||||
Iterator<Expression> iterator = node.astArguments().iterator();
|
UExpression arg = node.getValueArguments().get(parameter);
|
||||||
Expression argument = null;
|
long value = getLongValue(arg);
|
||||||
for (int i = 0; i <= parameter; i++) {
|
|
||||||
if (!iterator.hasNext()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
argument = iterator.next();
|
|
||||||
}
|
|
||||||
if (argument == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long value = getLongValue(context, argument);
|
|
||||||
if (value < min) {
|
if (value < min) {
|
||||||
String message = String.format("Value will be forced up to %d as of Android 5.1; "
|
String message = String.format("Value will be forced up to %d as of Android 5.1; "
|
||||||
+ "don't rely on this to be exact", min);
|
+ "don't rely on this to be exact", min);
|
||||||
context.report(ISSUE, argument, context.getLocation(argument), message);
|
context.report(ISSUE, arg, context.getLocation(arg), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getLongValue(@NonNull JavaContext context, @NonNull Expression argument) {
|
private static long getLongValue(@NonNull UExpression argument) {
|
||||||
Object value = ConstantEvaluator.evaluate(context, argument);
|
Object value = argument.evaluate();
|
||||||
if (value instanceof Number) {
|
if (value instanceof Number) {
|
||||||
return ((Number)value).longValue();
|
return ((Number)value).longValue();
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-38
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ATTR_SHOW_AS_ACTION;
|
import static com.android.SdkConstants.ATTR_SHOW_AS_ACTION;
|
||||||
import static com.android.SdkConstants.VALUE_ALWAYS;
|
import static com.android.SdkConstants.VALUE_ALWAYS;
|
||||||
@@ -22,19 +22,26 @@ import static com.android.SdkConstants.VALUE_IF_ROOM;
|
|||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector.JavaScanner;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.JavaContext;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.uast.UElement;
|
||||||
|
import org.jetbrains.uast.UQualifiedExpression;
|
||||||
|
import org.jetbrains.uast.USimpleReferenceExpression;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -42,17 +49,12 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
import lombok.ast.Select;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check which looks for usage of showAsAction="always" in menus (or
|
* Check which looks for usage of showAsAction="always" in menus (or
|
||||||
* MenuItem.SHOW_AS_ACTION_ALWAYS in code), which is usually a style guide violation.
|
* MenuItem.SHOW_AS_ACTION_ALWAYS in code), which is usually a style guide violation.
|
||||||
* (Use ifRoom instead).
|
* (Use ifRoom instead).
|
||||||
*/
|
*/
|
||||||
public class AlwaysShowActionDetector extends ResourceXmlDetector implements JavaScanner {
|
public class AlwaysShowActionDetector extends ResourceXmlDetector implements UastScanner {
|
||||||
|
|
||||||
/** The main issue discovered by this detector */
|
/** The main issue discovered by this detector */
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -78,7 +80,7 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav
|
|||||||
Severity.WARNING,
|
Severity.WARNING,
|
||||||
new Implementation(
|
new Implementation(
|
||||||
AlwaysShowActionDetector.class,
|
AlwaysShowActionDetector.class,
|
||||||
Scope.JAVA_AND_RESOURCE_FILES,
|
Scope.SOURCE_AND_RESOURCE_FILES,
|
||||||
Scope.RESOURCE_FILE_SCOPE))
|
Scope.RESOURCE_FILE_SCOPE))
|
||||||
.addMoreInfo("http://developer.android.com/design/patterns/actionbar.html"); //$NON-NLS-1$
|
.addMoreInfo("http://developer.android.com/design/patterns/actionbar.html"); //$NON-NLS-1$
|
||||||
|
|
||||||
@@ -193,47 +195,47 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav
|
|||||||
mFileAttributes.add(attribute);
|
mFileAttributes.add(attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public UastVisitor createUastVisitor(UastAndroidContext context) {
|
||||||
List<Class<? extends Node>> getApplicableNodeTypes() {
|
|
||||||
return Collections.<Class<? extends Node>>singletonList(Select.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
|
||||||
return new FieldAccessChecker(context);
|
return new FieldAccessChecker(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FieldAccessChecker extends ForwardingAstVisitor {
|
private class FieldAccessChecker extends UastVisitor {
|
||||||
private final JavaContext mContext;
|
private final UastAndroidContext mContext;
|
||||||
|
|
||||||
public FieldAccessChecker(JavaContext context) {
|
public FieldAccessChecker(UastAndroidContext context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitSelect(Select node) {
|
public boolean visitQualifiedExpression(@NotNull UQualifiedExpression node) {
|
||||||
String description = node.astIdentifier().astValue();
|
UElement selector = node.getSelector();
|
||||||
|
if (!(selector instanceof USimpleReferenceExpression)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String description = ((USimpleReferenceExpression)selector).getIdentifier();
|
||||||
boolean isIfRoom = description.equals("SHOW_AS_ACTION_IF_ROOM"); //$NON-NLS-1$
|
boolean isIfRoom = description.equals("SHOW_AS_ACTION_IF_ROOM"); //$NON-NLS-1$
|
||||||
boolean isAlways = description.equals("SHOW_AS_ACTION_ALWAYS"); //$NON-NLS-1$
|
boolean isAlways = description.equals("SHOW_AS_ACTION_ALWAYS"); //$NON-NLS-1$
|
||||||
if ((isIfRoom || isAlways)
|
if ((isIfRoom || isAlways)
|
||||||
&& node.astOperand().toString().equals("MenuItem")) { //$NON-NLS-1$
|
&& node.getReceiver().renderString().equals("MenuItem")) { //$NON-NLS-1$
|
||||||
if (isAlways) {
|
if (isAlways) {
|
||||||
if (mContext.getDriver().isSuppressed(mContext, ISSUE, node)) {
|
JavaContext lintContext = mContext.getLintContext();
|
||||||
return super.visitSelect(node);
|
if (lintContext.getDriver().isSuppressed(lintContext, ISSUE, node)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (mAlwaysFields == null) {
|
if (mAlwaysFields == null) {
|
||||||
mAlwaysFields = new ArrayList<Location>();
|
mAlwaysFields = new ArrayList<Location>();
|
||||||
}
|
}
|
||||||
mAlwaysFields.add(mContext.getLocation(node));
|
mAlwaysFields.add(UastAndroidUtils.getLocation(node));
|
||||||
} else {
|
} else {
|
||||||
mHasIfRoomRefs = true;
|
mHasIfRoomRefs = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.visitSelect(node);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-90
@@ -14,51 +14,36 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.FQCN_SUPPRESS_LINT;
|
import static com.android.SdkConstants.FQCN_SUPPRESS_LINT;
|
||||||
import static com.android.SdkConstants.SUPPRESS_LINT;
|
import static com.android.SdkConstants.SUPPRESS_LINT;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.client.api.IssueRegistry;
|
import com.android.tools.klint.client.api.IssueRegistry;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.ast.Annotation;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import lombok.ast.AnnotationElement;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.AnnotationValue;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.ArrayInitializer;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.Block;
|
import org.jetbrains.uast.java.JavaUastCallKinds;
|
||||||
import lombok.ast.ConstructorDeclaration;
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
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.VariableDefinition;
|
|
||||||
import lombok.ast.VariableDefinitionEntry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks annotations to make sure they are valid
|
* Checks annotations to make sure they are valid
|
||||||
*/
|
*/
|
||||||
public class AnnotationDetector extends Detector implements Detector.JavaScanner {
|
public class AnnotationDetector extends Detector implements UastScanner {
|
||||||
/** Placing SuppressLint on a local variable doesn't work for class-file based checks */
|
/** Placing SuppressLint on a local variable doesn't work for class-file based checks */
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"LocalSuppress", //$NON-NLS-1$
|
"LocalSuppress", //$NON-NLS-1$
|
||||||
@@ -94,59 +79,45 @@ public class AnnotationDetector extends Detector implements Detector.JavaScanner
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
public UastVisitor createUastVisitor(UastAndroidContext context) {
|
||||||
return Collections.<Class<? extends Node>>singletonList(Annotation.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
|
||||||
return new AnnotationChecker(context);
|
return new AnnotationChecker(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class AnnotationChecker extends ForwardingAstVisitor {
|
private static class AnnotationChecker extends UastVisitor {
|
||||||
private final JavaContext mContext;
|
private final UastAndroidContext mContext;
|
||||||
|
|
||||||
public AnnotationChecker(JavaContext context) {
|
public AnnotationChecker(UastAndroidContext context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitAnnotation(Annotation node) {
|
public boolean visitAnnotation(@NotNull UAnnotation node) {
|
||||||
String type = node.astAnnotationTypeReference().getTypeName();
|
String type = node.getName();
|
||||||
if (SUPPRESS_LINT.equals(type) || FQCN_SUPPRESS_LINT.equals(type)) {
|
if (SUPPRESS_LINT.equals(type) || FQCN_SUPPRESS_LINT.equals(type)) {
|
||||||
Node parent = node.getParent();
|
UElement parent = node.getParent();
|
||||||
if (parent instanceof Modifiers) {
|
if (parent instanceof UVariable) {
|
||||||
parent = parent.getParent();
|
for (UNamedExpression element : node.getValueArguments()) {
|
||||||
if (parent instanceof VariableDefinition) {
|
UExpression valueNode = element.getExpression();
|
||||||
for (AnnotationElement element : node.astElements()) {
|
if (UastLiteralUtils.isStringLiteral(valueNode)) {
|
||||||
AnnotationValue valueNode = element.astValue();
|
ULiteralExpression literal = (ULiteralExpression) valueNode;
|
||||||
if (valueNode == null) {
|
String id = ((String)literal.getValue());
|
||||||
|
if (!checkId(node, id)) {
|
||||||
|
return super.visitAnnotation(node);
|
||||||
|
}
|
||||||
|
} else if (valueNode instanceof UCallExpression &&
|
||||||
|
((UCallExpression) valueNode).getKind() == JavaUastCallKinds.ARRAY_INITIALIZER) {
|
||||||
|
UCallExpression array = (UCallExpression) valueNode;
|
||||||
|
if (array.getValueArgumentCount() == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (valueNode instanceof StringLiteral) {
|
for (UExpression arrayElement : array.getValueArguments()) {
|
||||||
StringLiteral literal = (StringLiteral) valueNode;
|
if (UastLiteralUtils.isStringLiteral(arrayElement)) {
|
||||||
String id = literal.astValue();
|
String id = ((String)((ULiteralExpression)arrayElement).getValue());
|
||||||
if (!checkId(node, id)) {
|
if (!checkId(node, id)) {
|
||||||
return super.visitAnnotation(node);
|
return super.visitAnnotation(node);
|
||||||
}
|
|
||||||
} else if (valueNode instanceof ArrayInitializer) {
|
|
||||||
ArrayInitializer array = (ArrayInitializer) valueNode;
|
|
||||||
StrictListAccessor<Expression, ArrayInitializer> expressions =
|
|
||||||
array.astExpressions();
|
|
||||||
if (expressions == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Iterator<Expression> arrayIterator = expressions.iterator();
|
|
||||||
while (arrayIterator.hasNext()) {
|
|
||||||
Expression arrayElement = arrayIterator.next();
|
|
||||||
if (arrayElement instanceof StringLiteral) {
|
|
||||||
String id = ((StringLiteral) arrayElement).astValue();
|
|
||||||
if (!checkId(node, id)) {
|
|
||||||
return super.visitAnnotation(node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,32 +126,26 @@ public class AnnotationDetector extends Detector implements Detector.JavaScanner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.visitAnnotation(node);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkId(Annotation node, String id) {
|
private boolean checkId(UAnnotation node, String id) {
|
||||||
IssueRegistry registry = mContext.getDriver().getRegistry();
|
IssueRegistry registry = mContext.getLintContext().getDriver().getRegistry();
|
||||||
Issue issue = registry.getIssue(id);
|
Issue issue = registry.getIssue(id);
|
||||||
// Special-case the ApiDetector issue, since it does both source file analysis
|
// Special-case the ApiDetector issue, since it does both source file analysis
|
||||||
// only on field references, and class file analysis on the rest, so we allow
|
// only on field references, and class file analysis on the rest, so we allow
|
||||||
// annotations outside of methods only on fields
|
// annotations outside of methods only on fields
|
||||||
if (issue != null && !issue.getImplementation().getScope().contains(Scope.JAVA_FILE)
|
if (issue != null && !issue.getImplementation().getScope().contains(Scope.SOURCE_FILE)
|
||||||
|| issue == ApiDetector.UNSUPPORTED) {
|
|| issue == ApiDetector.UNSUPPORTED) {
|
||||||
// Ensure that this isn't a field
|
// Ensure that this isn't a field
|
||||||
Node parent = node.getParent();
|
UElement parent = node.getParent();
|
||||||
while (parent != null) {
|
while (parent != null) {
|
||||||
if (parent instanceof MethodDeclaration
|
if (parent instanceof UFunction || parent instanceof UBlockExpression) {
|
||||||
|| parent instanceof ConstructorDeclaration
|
|
||||||
|| parent instanceof Block) {
|
|
||||||
break;
|
break;
|
||||||
} else if (parent instanceof TypeBody) { // It's a field
|
} else if (issue == ApiDetector.UNSUPPORTED && parent instanceof UDeclarationsExpression) {
|
||||||
return true;
|
UDeclarationsExpression declarations = (UDeclarationsExpression)parent;
|
||||||
} else if (issue == ApiDetector.UNSUPPORTED
|
for (UVariable var : declarations.getVariables()) {
|
||||||
&& parent instanceof VariableDefinition) {
|
if (var.getKind() != UastVariableKind.MEMBER && var.getInitializer() instanceof UQualifiedExpression) {
|
||||||
VariableDefinition definition = (VariableDefinition) parent;
|
|
||||||
for (VariableDefinitionEntry entry : definition.astVariables()) {
|
|
||||||
Expression initializer = entry.astInitializer();
|
|
||||||
if (initializer instanceof Select) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +158,7 @@ public class AnnotationDetector extends Detector implements Detector.JavaScanner
|
|||||||
|
|
||||||
// This issue doesn't have AST access: annotations are not
|
// This issue doesn't have AST access: annotations are not
|
||||||
// available for local variables or parameters
|
// available for local variables or parameters
|
||||||
mContext.report(ISSUE, node, mContext.getLocation(node), String.format(
|
mContext.report(ISSUE, node, UastAndroidUtils.getLocation(node), String.format(
|
||||||
"The `@SuppressLint` annotation cannot be used on a local " +
|
"The `@SuppressLint` annotation cannot be used on a local " +
|
||||||
"variable with the lint check '%1$s': move out to the " +
|
"variable with the lint check '%1$s': move out to the " +
|
||||||
"surrounding method", id));
|
"surrounding method", id));
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
|
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CONSTRUCTOR_NAME;
|
import static com.android.SdkConstants.CONSTRUCTOR_NAME;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_PREFIX;
|
import static com.android.SdkConstants.ANDROID_PREFIX;
|
||||||
import static com.android.SdkConstants.ANDROID_THEME_PREFIX;
|
import static com.android.SdkConstants.ANDROID_THEME_PREFIX;
|
||||||
@@ -34,7 +34,6 @@ import static com.android.SdkConstants.CHECK_BOX;
|
|||||||
import static com.android.SdkConstants.CLASS_CONSTRUCTOR;
|
import static com.android.SdkConstants.CLASS_CONSTRUCTOR;
|
||||||
import static com.android.SdkConstants.CONSTRUCTOR_NAME;
|
import static com.android.SdkConstants.CONSTRUCTOR_NAME;
|
||||||
import static com.android.SdkConstants.PREFIX_ANDROID;
|
import static com.android.SdkConstants.PREFIX_ANDROID;
|
||||||
import static com.android.SdkConstants.R_CLASS;
|
|
||||||
import static com.android.SdkConstants.SWITCH;
|
import static com.android.SdkConstants.SWITCH;
|
||||||
import static com.android.SdkConstants.TAG;
|
import static com.android.SdkConstants.TAG;
|
||||||
import static com.android.SdkConstants.TAG_ITEM;
|
import static com.android.SdkConstants.TAG_ITEM;
|
||||||
@@ -42,12 +41,10 @@ import static com.android.SdkConstants.TAG_STYLE;
|
|||||||
import static com.android.SdkConstants.TARGET_API;
|
import static com.android.SdkConstants.TARGET_API;
|
||||||
import static com.android.SdkConstants.TOOLS_URI;
|
import static com.android.SdkConstants.TOOLS_URI;
|
||||||
import static com.android.SdkConstants.VIEW_TAG;
|
import static com.android.SdkConstants.VIEW_TAG;
|
||||||
import static com.android.tools.lint.detector.api.ClassContext.getFqcn;
|
import static com.android.tools.klint.detector.api.LintUtils.getNextInstruction;
|
||||||
import static com.android.tools.lint.detector.api.ClassContext.getInternalName;
|
import static com.android.tools.klint.detector.api.Location.SearchDirection.BACKWARD;
|
||||||
import static com.android.tools.lint.detector.api.LintUtils.getNextInstruction;
|
import static com.android.tools.klint.detector.api.Location.SearchDirection.FORWARD;
|
||||||
import static com.android.tools.lint.detector.api.Location.SearchDirection.BACKWARD;
|
import static com.android.tools.klint.detector.api.Location.SearchDirection.NEAREST;
|
||||||
import static com.android.tools.lint.detector.api.Location.SearchDirection.FORWARD;
|
|
||||||
import static com.android.tools.lint.detector.api.Location.SearchDirection.NEAREST;
|
|
||||||
import static com.android.utils.SdkUtils.getResourceFieldName;
|
import static com.android.utils.SdkUtils.getResourceFieldName;
|
||||||
|
|
||||||
import com.android.SdkConstants;
|
import com.android.SdkConstants;
|
||||||
@@ -56,32 +53,27 @@ import com.android.annotations.Nullable;
|
|||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.sdklib.AndroidVersion;
|
import com.android.sdklib.AndroidVersion;
|
||||||
import com.android.sdklib.SdkVersionInfo;
|
import com.android.sdklib.SdkVersionInfo;
|
||||||
import com.android.tools.lint.client.api.IssueRegistry;
|
import com.android.tools.klint.client.api.IssueRegistry;
|
||||||
import com.android.tools.lint.client.api.JavaParser;
|
import com.android.tools.klint.client.api.LintDriver;
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.ClassContext;
|
||||||
import com.android.tools.lint.detector.api.ClassContext;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.DefaultPosition;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Location.SearchHints;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Location.SearchHints;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Position;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
|
||||||
import com.android.tools.lint.detector.api.TextFormat;
|
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
|
||||||
import com.android.utils.Pair;
|
import com.android.utils.Pair;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
|
import org.jetbrains.uast.*;
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
@@ -91,64 +83,29 @@ import org.objectweb.asm.tree.FieldInsnNode;
|
|||||||
import org.objectweb.asm.tree.FieldNode;
|
import org.objectweb.asm.tree.FieldNode;
|
||||||
import org.objectweb.asm.tree.InsnList;
|
import org.objectweb.asm.tree.InsnList;
|
||||||
import org.objectweb.asm.tree.IntInsnNode;
|
import org.objectweb.asm.tree.IntInsnNode;
|
||||||
import org.objectweb.asm.tree.JumpInsnNode;
|
|
||||||
import org.objectweb.asm.tree.LdcInsnNode;
|
import org.objectweb.asm.tree.LdcInsnNode;
|
||||||
import org.objectweb.asm.tree.LocalVariableNode;
|
import org.objectweb.asm.tree.LocalVariableNode;
|
||||||
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
import org.objectweb.asm.tree.analysis.AnalyzerException;
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import lombok.ast.Annotation;
|
|
||||||
import lombok.ast.AnnotationElement;
|
|
||||||
import lombok.ast.AnnotationValue;
|
|
||||||
import lombok.ast.AstVisitor;
|
|
||||||
import lombok.ast.BinaryExpression;
|
|
||||||
import lombok.ast.Case;
|
|
||||||
import lombok.ast.Catch;
|
|
||||||
import lombok.ast.ClassDeclaration;
|
|
||||||
import lombok.ast.ConstructorDeclaration;
|
|
||||||
import lombok.ast.ConstructorInvocation;
|
|
||||||
import lombok.ast.Expression;
|
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
|
||||||
import lombok.ast.If;
|
|
||||||
import lombok.ast.ImportDeclaration;
|
|
||||||
import lombok.ast.InlineIfExpression;
|
|
||||||
import lombok.ast.IntegralLiteral;
|
|
||||||
import lombok.ast.MethodDeclaration;
|
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.Modifiers;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for usages of APIs that are not supported in all the versions targeted
|
* Looks for usages of APIs that are not supported in all the versions targeted
|
||||||
* by this application (according to its minimum API requirement in the manifest).
|
* by this application (according to its minimum API requirement in the manifest).
|
||||||
*/
|
*/
|
||||||
public class ApiDetector extends ResourceXmlDetector
|
public class ApiDetector extends ResourceXmlDetector
|
||||||
implements Detector.ClassScanner, Detector.JavaScanner {
|
implements Detector.ClassScanner, UastScanner {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether we flag variable, field, parameter and return type declarations of a type
|
* Whether we flag variable, field, parameter and return type declarations of a type
|
||||||
@@ -1386,9 +1343,9 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
super.afterCheckProject(context);
|
super.afterCheckProject(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Nullable
|
/* @Nullable
|
||||||
@Override
|
@Override
|
||||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
||||||
if (mApiDatabase == null) {
|
if (mApiDatabase == null) {
|
||||||
@@ -1413,7 +1370,7 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
*//**
|
||||||
* Checks whether the given instruction is a benign usage of a constant defined in
|
* Checks whether the given instruction is a benign usage of a constant defined in
|
||||||
* a later version of Android than the application's {@code minSdkVersion}.
|
* a later version of Android than the application's {@code minSdkVersion}.
|
||||||
*
|
*
|
||||||
@@ -1422,7 +1379,18 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
* @param owner the field owner
|
* @param owner the field owner
|
||||||
* @return true if the given usage is safe on older versions than the introduction
|
* @return true if the given usage is safe on older versions than the introduction
|
||||||
* level of the constant
|
* level of the constant
|
||||||
*/
|
*//*
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static boolean isBenignConstantUsage(
|
||||||
|
@Nullable UElement node,
|
||||||
|
@NonNull String name,
|
||||||
|
@NonNull String owner) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public static boolean isBenignConstantUsage(
|
public static boolean isBenignConstantUsage(
|
||||||
@Nullable lombok.ast.Node node,
|
@Nullable lombok.ast.Node node,
|
||||||
@NonNull String name,
|
@NonNull String name,
|
||||||
@@ -1811,10 +1779,10 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
super.endVisit(node);
|
super.endVisit(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
*//**
|
||||||
* Checks a Java source field reference. Returns true if the field is known
|
* Checks a Java source field reference. Returns true if the field is known
|
||||||
* regardless of whether it's an invalid field or not
|
* regardless of whether it's an invalid field or not
|
||||||
*/
|
*//*
|
||||||
private boolean checkField(
|
private boolean checkField(
|
||||||
@NonNull lombok.ast.Node node,
|
@NonNull lombok.ast.Node node,
|
||||||
@NonNull String name,
|
@NonNull String name,
|
||||||
@@ -1902,12 +1870,12 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
*//**
|
||||||
* Returns the minimum SDK to use according to the given AST node, or null
|
* Returns the minimum SDK to use according to the given AST node, or null
|
||||||
* if no {@code TargetApi} annotations were found
|
* if no {@code TargetApi} annotations were found
|
||||||
*
|
*
|
||||||
* @return the API level to use for this node, or -1
|
* @return the API level to use for this node, or -1
|
||||||
*/
|
*//*
|
||||||
public int getLocalMinSdk(@Nullable lombok.ast.Node scope) {
|
public int getLocalMinSdk(@Nullable lombok.ast.Node scope) {
|
||||||
while (scope != null) {
|
while (scope != null) {
|
||||||
Class<? extends lombok.ast.Node> type = scope.getClass();
|
Class<? extends lombok.ast.Node> type = scope.getClass();
|
||||||
@@ -1952,13 +1920,13 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
*//**
|
||||||
* Returns the API level for the given AST node if specified with
|
* Returns the API level for the given AST node if specified with
|
||||||
* an {@code @TargetApi} annotation.
|
* an {@code @TargetApi} annotation.
|
||||||
*
|
*
|
||||||
* @param modifiers the modifier to check
|
* @param modifiers the modifier to check
|
||||||
* @return the target API level, or -1 if not specified
|
* @return the target API level, or -1 if not specified
|
||||||
*/
|
*//*
|
||||||
public static int getTargetApi(@Nullable Modifiers modifiers) {
|
public static int getTargetApi(@Nullable Modifiers modifiers) {
|
||||||
if (modifiers == null) {
|
if (modifiers == null) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2000,6 +1968,36 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public static int getTargetApi(List<UAnnotation> annotations) {
|
||||||
|
if (annotations == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UAnnotation annotation : annotations) {
|
||||||
|
if (annotation.matchesName(TARGET_API)) {
|
||||||
|
for (UNamedExpression element : annotation.getValueArguments()) {
|
||||||
|
UExpression valueNode = element.getExpression();
|
||||||
|
if (UastLiteralUtils.isIntegralLiteral(valueNode)) {
|
||||||
|
return (int) UastLiteralUtils.getLongValue((ULiteralExpression) valueNode);
|
||||||
|
} else if (UastLiteralUtils.isStringLiteral(valueNode)) {
|
||||||
|
String value = (String) ((ULiteralExpression) valueNode).getValue();
|
||||||
|
return SdkVersionInfo.getApiByBuildCode(value, true);
|
||||||
|
} else if (valueNode instanceof UQualifiedExpression) {
|
||||||
|
UQualifiedExpression select = (UQualifiedExpression) valueNode;
|
||||||
|
String codename = select.getSelector().renderString();
|
||||||
|
return SdkVersionInfo.getApiByBuildCode(codename, true);
|
||||||
|
} else if (valueNode instanceof USimpleReferenceExpression) {
|
||||||
|
USimpleReferenceExpression reference = (USimpleReferenceExpression) valueNode;
|
||||||
|
String codename = reference.getIdentifier();
|
||||||
|
return SdkVersionInfo.getApiByBuildCode(codename, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2023,7 +2021,7 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
@NonNull ClassNode classNode,
|
@NonNull ClassNode classNode,
|
||||||
@NonNull MethodNode method,
|
@NonNull MethodNode method,
|
||||||
@NonNull AbstractInsnNode call,
|
@NonNull AbstractInsnNode call,
|
||||||
int requiredApi) {
|
int requiredApi) { return false; } /*
|
||||||
assert requiredApi != -1;
|
assert requiredApi != -1;
|
||||||
|
|
||||||
if (!containsSimpleSdkCheck(method)) {
|
if (!containsSimpleSdkCheck(method)) {
|
||||||
@@ -2126,10 +2124,10 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
*//**
|
||||||
* Control flow graph which skips control flow edges that check
|
* Control flow graph which skips control flow edges that check
|
||||||
* a given SDK_VERSION requirement that is not met by a given call
|
* a given SDK_VERSION requirement that is not met by a given call
|
||||||
*/
|
*//*
|
||||||
private static class ApiCheckGraph extends ControlFlowGraph {
|
private static class ApiCheckGraph extends ControlFlowGraph {
|
||||||
private final int mRequiredApi;
|
private final int mRequiredApi;
|
||||||
|
|
||||||
@@ -2177,5 +2175,5 @@ public class ApiDetector extends ResourceXmlDetector
|
|||||||
|
|
||||||
super.add(from, to);
|
super.add(from, to);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_PKG;
|
import static com.android.SdkConstants.ANDROID_PKG;
|
||||||
import static com.android.SdkConstants.DOT_XML;
|
import static com.android.SdkConstants.DOT_XML;
|
||||||
@@ -26,8 +26,8 @@ import com.android.sdklib.repository.FullRevision;
|
|||||||
import com.android.sdklib.repository.descriptors.PkgType;
|
import com.android.sdklib.repository.descriptors.PkgType;
|
||||||
import com.android.sdklib.repository.local.LocalPkgInfo;
|
import com.android.sdklib.repository.local.LocalPkgInfo;
|
||||||
import com.android.sdklib.repository.local.LocalSdk;
|
import com.android.sdklib.repository.local.LocalSdk;
|
||||||
import com.android.tools.lint.client.api.LintClient;
|
import com.android.tools.klint.client.api.LintClient;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
|
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
|
|||||||
+38
-47
@@ -13,37 +13,37 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.APPCOMPAT_LIB_ARTIFACT;
|
import static com.android.SdkConstants.APPCOMPAT_LIB_ARTIFACT;
|
||||||
import static com.android.SdkConstants.CLASS_ACTIVITY;
|
import static com.android.SdkConstants.CLASS_ACTIVITY;
|
||||||
import static com.android.tools.lint.detector.api.TextFormat.RAW;
|
import static com.android.tools.klint.detector.api.TextFormat.RAW;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
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.TextFormat;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.UCallExpression;
|
||||||
import lombok.ast.ClassDeclaration;
|
import org.jetbrains.uast.UClass;
|
||||||
import lombok.ast.MethodInvocation;
|
import org.jetbrains.uast.UFunction;
|
||||||
|
import org.jetbrains.uast.UastUtils;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
|
||||||
public class AppCompatCallDetector extends Detector implements Detector.JavaScanner {
|
public class AppCompatCallDetector extends Detector implements UastScanner {
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"AppCompatMethod",
|
"AppCompatMethod",
|
||||||
"Using Wrong AppCompat Method",
|
"Using Wrong AppCompat Method",
|
||||||
@@ -82,23 +82,21 @@ public class AppCompatCallDetector extends Detector implements Detector.JavaScan
|
|||||||
mDependsOnAppCompat = dependsOnAppCompat != null && dependsOnAppCompat;
|
mDependsOnAppCompat = dependsOnAppCompat != null && dependsOnAppCompat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getApplicableMethodNames() {
|
public List<String> getApplicableFunctionNames() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
GET_ACTION_BAR,
|
GET_ACTION_BAR,
|
||||||
START_ACTION_MODE,
|
START_ACTION_MODE,
|
||||||
SET_PROGRESS_BAR_VIS,
|
SET_PROGRESS_BAR_VIS,
|
||||||
SET_PROGRESS_BAR_IN_VIS,
|
SET_PROGRESS_BAR_IN_VIS,
|
||||||
SET_PROGRESS_BAR_INDETERMINATE,
|
SET_PROGRESS_BAR_INDETERMINATE,
|
||||||
REQUEST_WINDOW_FEATURE);
|
REQUEST_WINDOW_FEATURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation node) {
|
|
||||||
if (mDependsOnAppCompat && isAppBarActivityCall(context, node)) {
|
if (mDependsOnAppCompat && isAppBarActivityCall(context, node)) {
|
||||||
String name = node.astName().astValue();
|
String name = node.getFunctionName();
|
||||||
String replace = null;
|
String replace = null;
|
||||||
if (GET_ACTION_BAR.equals(name)) {
|
if (GET_ACTION_BAR.equals(name)) {
|
||||||
replace = "getSupportActionBar";
|
replace = "getSupportActionBar";
|
||||||
@@ -116,29 +114,22 @@ public class AppCompatCallDetector extends Detector implements Detector.JavaScan
|
|||||||
|
|
||||||
if (replace != null) {
|
if (replace != null) {
|
||||||
String message = String.format(ERROR_MESSAGE_FORMAT, replace, name);
|
String message = String.format(ERROR_MESSAGE_FORMAT, replace, name);
|
||||||
context.report(ISSUE, node, context.getLocation(node), message);
|
context.report(ISSUE, node, UastAndroidUtils.getLocation(node), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAppBarActivityCall(@NonNull JavaContext context,
|
private static boolean isAppBarActivityCall(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation node) {
|
@NonNull UCallExpression node) {
|
||||||
ResolvedNode resolved = context.resolve(node);
|
UFunction resolved = node.resolve(context);
|
||||||
if (resolved instanceof ResolvedMethod) {
|
if (resolved != null) {
|
||||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
UClass containingClass = UastUtils.getContainingClass(resolved);
|
||||||
ResolvedClass containingClass = method.getContainingClass();
|
if (containingClass != null && containingClass.isSubclassOf(CLASS_ACTIVITY)) {
|
||||||
if (containingClass.isSubclassOf(CLASS_ACTIVITY, false)) {
|
|
||||||
// Make sure that the calling context is a subclass of ActionBarActivity;
|
// Make sure that the calling context is a subclass of ActionBarActivity;
|
||||||
// we don't want to flag these calls if they are in non-appcompat activities
|
// we don't want to flag these calls if they are in non-appcompat activities
|
||||||
// such as PreferenceActivity (see b.android.com/58512)
|
// such as PreferenceActivity (see b.android.com/58512)
|
||||||
ClassDeclaration surroundingClass = JavaContext.findSurroundingClass(node);
|
return UastUtils.getContainingClassOrEmpty(node)
|
||||||
if (surroundingClass != null) {
|
.isSubclassOf("android.support.v7.app.ActionBarActivity");
|
||||||
ResolvedNode clz = context.resolve(surroundingClass);
|
|
||||||
return clz instanceof ResolvedClass &&
|
|
||||||
((ResolvedClass)clz).isSubclassOf(
|
|
||||||
"android.support.v7.app.ActionBarActivity",
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+12
-12
@@ -14,24 +14,24 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
import static com.android.SdkConstants.ATTR_SHOW_AS_ACTION;
|
import static com.android.SdkConstants.ATTR_SHOW_AS_ACTION;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Detector.JavaScanner;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
|
||||||
|
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -43,7 +43,7 @@ import java.util.Collections;
|
|||||||
* Using app:showAsAction instead of android:showAsAction leads to problems, but
|
* Using app:showAsAction instead of android:showAsAction leads to problems, but
|
||||||
* isn't caught by the API Detector since it's not in the Android namespace.
|
* isn't caught by the API Detector since it's not in the Android namespace.
|
||||||
*/
|
*/
|
||||||
public class AppCompatResourceDetector extends ResourceXmlDetector implements JavaScanner {
|
public class AppCompatResourceDetector extends ResourceXmlDetector implements UastScanner {
|
||||||
/** The main issue discovered by this detector */
|
/** The main issue discovered by this detector */
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"AppCompatResource", //$NON-NLS-1$
|
"AppCompatResource", //$NON-NLS-1$
|
||||||
|
|||||||
+10
-10
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
import static com.android.SdkConstants.ATTR_HOST;
|
import static com.android.SdkConstants.ATTR_HOST;
|
||||||
@@ -38,15 +38,15 @@ import com.android.ide.common.res2.AbstractResourceRepository;
|
|||||||
import com.android.ide.common.res2.ResourceItem;
|
import com.android.ide.common.res2.ResourceItem;
|
||||||
import com.android.ide.common.resources.ResourceUrl;
|
import com.android.ide.common.resources.ResourceUrl;
|
||||||
import com.android.resources.ResourceType;
|
import com.android.resources.ResourceType;
|
||||||
import com.android.tools.lint.client.api.LintClient;
|
import com.android.tools.klint.client.api.LintClient;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|||||||
+14
-14
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
|
|
||||||
import static com.android.SdkConstants.ATTR_NAME;
|
import static com.android.SdkConstants.ATTR_NAME;
|
||||||
@@ -30,19 +30,19 @@ import com.android.ide.common.res2.ResourceFile;
|
|||||||
import com.android.ide.common.res2.ResourceItem;
|
import com.android.ide.common.res2.ResourceItem;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.resources.ResourceType;
|
import com.android.resources.ResourceType;
|
||||||
import com.android.tools.lint.client.api.LintClient;
|
import com.android.tools.klint.client.api.LintClient;
|
||||||
import com.android.tools.lint.client.api.LintDriver;
|
import com.android.tools.klint.client.api.LintDriver;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.utils.Pair;
|
import com.android.utils.Pair;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|||||||
@@ -14,35 +14,33 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.ast.Assert;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.BinaryExpression;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.BooleanLiteral;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Expression;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
import org.jetbrains.uast.java.JavaSpecialExpressionKinds;
|
||||||
import lombok.ast.Node;
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
import lombok.ast.NullLiteral;
|
|
||||||
|
import static org.jetbrains.uast.UastLiteralUtils.isNullLiteral;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for assertion usages.
|
* Looks for assertion usages.
|
||||||
*/
|
*/
|
||||||
public class AssertDetector extends Detector implements Detector.JavaScanner {
|
public class AssertDetector extends Detector implements UastScanner {
|
||||||
/** Using assertions */
|
/** Using assertions */
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"Assert", //$NON-NLS-1$
|
"Assert", //$NON-NLS-1$
|
||||||
@@ -80,28 +78,30 @@ public class AssertDetector extends Detector implements Detector.JavaScanner {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
public UastVisitor createUastVisitor(final UastAndroidContext context) {
|
||||||
return Collections.<Class<? extends Node>>singletonList(Assert.class);
|
return new UastVisitor() {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AstVisitor createJavaVisitor(@NonNull final JavaContext context) {
|
|
||||||
return new ForwardingAstVisitor() {
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitAssert(Assert node) {
|
public boolean visitSpecialExpressionList(@NotNull USpecialExpressionList node) {
|
||||||
if (!context.getMainProject().isAndroidProject()) {
|
if (node.getKind() != JavaSpecialExpressionKinds.ASSERT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression assertion = node.astAssertion();
|
if (!context.getLintContext().getMainProject().isAndroidProject()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UExpression assertion = node.firstOrNull();
|
||||||
// Allow "assert true"; it's basically a no-op
|
// Allow "assert true"; it's basically a no-op
|
||||||
if (assertion instanceof BooleanLiteral) {
|
if (assertion instanceof ULiteralExpression) {
|
||||||
Boolean b = ((BooleanLiteral) assertion).astValue();
|
ULiteralExpression literal = (ULiteralExpression) assertion;
|
||||||
if (b != null && b) {
|
if (literal.isBoolean()) {
|
||||||
return false;
|
Boolean b = ((Boolean)literal.getValue());
|
||||||
|
if (b != null && b) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Allow assertions of the form "assert foo != null" because they are often used
|
// Allow assertions of the form "assert foo != null" because they are often used
|
||||||
@@ -114,8 +114,8 @@ public class AssertDetector extends Detector implements Detector.JavaScanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
String message
|
String message
|
||||||
= "Assertions are unreliable. Use `BuildConfig.DEBUG` conditional checks instead.";
|
= "Assertions are unreliable. Use `BuildConfig.DEBUG` conditional checks instead.";
|
||||||
context.report(ISSUE, node, context.getLocation(node), message);
|
context.report(ISSUE, node, UastAndroidUtils.getLocation(node), message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -126,14 +126,14 @@ public class AssertDetector extends Detector implements Detector.JavaScanner {
|
|||||||
* true for expressions like "a != null" and "a != null && b != null" and
|
* true for expressions like "a != null" and "a != null && b != null" and
|
||||||
* "b == null || c != null".
|
* "b == null || c != null".
|
||||||
*/
|
*/
|
||||||
private static boolean isNullCheck(Expression expression) {
|
private static boolean isNullCheck(UExpression expression) {
|
||||||
if (expression instanceof BinaryExpression) {
|
if (expression instanceof UBinaryExpression) {
|
||||||
BinaryExpression binExp = (BinaryExpression) expression;
|
UBinaryExpression binExp = (UBinaryExpression) expression;
|
||||||
if (binExp.astLeft() instanceof NullLiteral ||
|
if (isNullLiteral(binExp.getLeftOperand()) ||
|
||||||
binExp.astRight() instanceof NullLiteral) {
|
isNullLiteral(binExp.getRightOperand())) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return isNullCheck(binExp.astLeft()) && isNullCheck(binExp.astRight());
|
return isNullCheck(binExp.getLeftOperand()) && isNullCheck(binExp.getRightOperand());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+5
-5
@@ -14,13 +14,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.VisibleForTesting;
|
import com.android.annotations.VisibleForTesting;
|
||||||
import com.android.tools.lint.client.api.IssueRegistry;
|
import com.android.tools.klint.client.api.IssueRegistry;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -283,7 +283,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
|
|||||||
initialSize += 10;
|
initialSize += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope.contains(Scope.JAVA_FILE)) {
|
if (scope.contains(Scope.SOURCE_FILE)) {
|
||||||
initialSize += 55;
|
initialSize += 55;
|
||||||
} else if (scope.contains(Scope.CLASS_FILE)) {
|
} else if (scope.contains(Scope.CLASS_FILE)) {
|
||||||
initialSize += 15;
|
initialSize += 15;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_STRING_PREFIX;
|
import static com.android.SdkConstants.ANDROID_STRING_PREFIX;
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
@@ -41,17 +41,17 @@ import static com.android.SdkConstants.VALUE_VERTICAL;
|
|||||||
import com.android.SdkConstants;
|
import com.android.SdkConstants;
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|||||||
+10
-10
@@ -14,21 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ATTR_NAME;
|
import static com.android.SdkConstants.ATTR_NAME;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
|
|
||||||
|
|||||||
+70
-81
@@ -14,42 +14,37 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CLASS_VIEW;
|
import static com.android.SdkConstants.CLASS_VIEW;
|
||||||
import static com.android.SdkConstants.SUPPORT_ANNOTATIONS_PREFIX;
|
import static com.android.SdkConstants.SUPPORT_ANNOTATIONS_PREFIX;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.client.api.JavaParser;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
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;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.MethodDeclaration;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.MethodInvocation;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Node;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.Super;
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure that methods call super when overriding methods.
|
* Makes sure that methods call super when overriding methods.
|
||||||
*/
|
*/
|
||||||
public class CallSuperDetector extends Detector implements Detector.JavaScanner {
|
public class CallSuperDetector extends Detector implements UastScanner {
|
||||||
private static final String CALL_SUPER_ANNOTATION = SUPPORT_ANNOTATIONS_PREFIX + "CallSuper"; //$NON-NLS-1$
|
private static final String CALL_SUPER_ANNOTATION = SUPPORT_ANNOTATIONS_PREFIX + "CallSuper"; //$NON-NLS-1$
|
||||||
private static final String ON_DETACHED_FROM_WINDOW = "onDetachedFromWindow"; //$NON-NLS-1$
|
private static final String ON_DETACHED_FROM_WINDOW = "onDetachedFromWindow"; //$NON-NLS-1$
|
||||||
private static final String ON_VISIBILITY_CHANGED = "onVisibilityChanged"; //$NON-NLS-1$
|
private static final String ON_VISIBILITY_CHANGED = "onVisibilityChanged"; //$NON-NLS-1$
|
||||||
@@ -86,40 +81,29 @@ public class CallSuperDetector extends Detector implements Detector.JavaScanner
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
public UastVisitor createUastVisitor(final UastAndroidContext context) {
|
||||||
return Collections.<Class<? extends Node>>singletonList(MethodDeclaration.class);
|
return new UastVisitor() {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AstVisitor createJavaVisitor(@NonNull final JavaContext context) {
|
|
||||||
return new ForwardingAstVisitor() {
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitMethodDeclaration(MethodDeclaration node) {
|
public boolean visitFunction(@NotNull UFunction node) {
|
||||||
ResolvedNode resolved = context.resolve(node);
|
checkCallSuper(context, node);
|
||||||
if (resolved instanceof ResolvedMethod) {
|
|
||||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
|
||||||
checkCallSuper(context, node, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkCallSuper(@NonNull JavaContext context,
|
private static void checkCallSuper(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodDeclaration declaration,
|
@NonNull UFunction declaration) {
|
||||||
@NonNull ResolvedMethod method) {
|
|
||||||
|
|
||||||
ResolvedMethod superMethod = getRequiredSuperMethod(method);
|
UFunction superMethod = getRequiredSuperMethod(context, declaration);
|
||||||
if (superMethod != null) {
|
if (superMethod != null) {
|
||||||
if (!SuperCallVisitor.callsSuper(context, declaration, superMethod)) {
|
if (!SuperCallVisitor.callsSuper(context, declaration, superMethod)) {
|
||||||
String methodName = method.getName();
|
String methodName = declaration.getName();
|
||||||
String message = "Overriding method should call `super."
|
String message = "Overriding method should call `super."
|
||||||
+ methodName + "`";
|
+ methodName + "`";
|
||||||
Location location = context.getLocation(declaration.astMethodName());
|
Location location = UastAndroidUtils.getLocation(declaration.getNameElement());
|
||||||
context.report(ISSUE, declaration, location, message);
|
context.report(ISSUE, declaration, location, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,8 +114,8 @@ public class CallSuperDetector extends Detector implements Detector.JavaScanner
|
|||||||
* to be invoked, and if so, returns it (otherwise returns null)
|
* to be invoked, and if so, returns it (otherwise returns null)
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private static ResolvedMethod getRequiredSuperMethod(
|
private static UFunction getRequiredSuperMethod(UastAndroidContext context,
|
||||||
@NonNull ResolvedMethod method) {
|
@NonNull UFunction method) {
|
||||||
|
|
||||||
String name = method.getName();
|
String name = method.getName();
|
||||||
if (ON_DETACHED_FROM_WINDOW.equals(name)) {
|
if (ON_DETACHED_FROM_WINDOW.equals(name)) {
|
||||||
@@ -140,84 +124,89 @@ public class CallSuperDetector extends Detector implements Detector.JavaScanner
|
|||||||
// is still dangerous if supporting older versions so flag
|
// is still dangerous if supporting older versions so flag
|
||||||
// this for now (should make annotation carry metadata like
|
// this for now (should make annotation carry metadata like
|
||||||
// compileSdkVersion >= N).
|
// compileSdkVersion >= N).
|
||||||
if (!method.getContainingClass().isSubclassOf(CLASS_VIEW, false)) {
|
if (!UastUtils.getContainingClassOrEmpty(method).isSubclassOf(CLASS_VIEW)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return method.getSuperMethod();
|
List<UFunction> superFunctions = method.getSuperFunctions(context);
|
||||||
|
return superFunctions.isEmpty() ? null : superFunctions.get(0);
|
||||||
} else if (ON_VISIBILITY_CHANGED.equals(name)) {
|
} else if (ON_VISIBILITY_CHANGED.equals(name)) {
|
||||||
// From Android Wear API; doesn't yet have an annotation
|
// From Android Wear API; doesn't yet have an annotation
|
||||||
// but we want to enforce this right away until the AAR
|
// but we want to enforce this right away until the AAR
|
||||||
// is updated to supply it once @CallSuper is available in
|
// is updated to supply it once @CallSuper is available in
|
||||||
// the support library
|
// the support library
|
||||||
if (!method.getContainingClass().isSubclassOf(
|
if (!UastUtils.getContainingClassOrEmpty(method).isSubclassOf(
|
||||||
"android.support.wearable.watchface.WatchFaceService.Engine", false)) {
|
"android.support.wearable.watchface.WatchFaceService.Engine")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return method.getSuperMethod();
|
List<UFunction> superFunctions = method.getSuperFunctions(context);
|
||||||
|
return superFunctions.isEmpty() ? null : superFunctions.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up annotations metadata
|
// Look up annotations metadata
|
||||||
ResolvedMethod directSuper = method.getSuperMethod();
|
List<UFunction> superFunctions = method.getSuperFunctions(context);
|
||||||
ResolvedMethod superMethod = directSuper;
|
UFunction directSuper = superFunctions.isEmpty() ? null : superFunctions.get(0);
|
||||||
|
UFunction superMethod = directSuper;
|
||||||
while (superMethod != null) {
|
while (superMethod != null) {
|
||||||
Iterable<JavaParser.ResolvedAnnotation> annotations = superMethod.getAnnotations();
|
for (UAnnotation annotation : superMethod.getAnnotations()) {
|
||||||
for (JavaParser.ResolvedAnnotation annotation : annotations) {
|
annotation = SupportAnnotationDetector.getRelevantAnnotation(context, annotation);
|
||||||
annotation = SupportAnnotationDetector.getRelevantAnnotation(annotation);
|
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
String signature = annotation.getSignature();
|
String signature = annotation.getFqName();
|
||||||
if (CALL_SUPER_ANNOTATION.equals(signature)) {
|
if (CALL_SUPER_ANNOTATION.equals(signature)) {
|
||||||
return directSuper;
|
return directSuper;
|
||||||
} else if (signature.endsWith(".OverrideMustInvoke")) {
|
} else if (signature != null && signature.endsWith(".OverrideMustInvoke")) {
|
||||||
// Handle findbugs annotation on the fly too
|
// Handle findbugs annotation on the fly too
|
||||||
return directSuper;
|
return directSuper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
superMethod = superMethod.getSuperMethod();
|
superFunctions = superMethod.getSuperFunctions(context);
|
||||||
|
superMethod = superFunctions.isEmpty() ? null : superFunctions.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Visits a method and determines whether the method calls its super method */
|
/** Visits a method and determines whether the method calls its super method */
|
||||||
private static class SuperCallVisitor extends ForwardingAstVisitor {
|
private static class SuperCallVisitor extends UastVisitor {
|
||||||
private final JavaContext mContext;
|
private final UastAndroidContext mContext;
|
||||||
private final ResolvedMethod mMethod;
|
private final String mMethodFqName;
|
||||||
private boolean mCallsSuper;
|
private boolean mCallsSuper;
|
||||||
|
|
||||||
public static boolean callsSuper(
|
public static boolean callsSuper(
|
||||||
@NonNull JavaContext context,
|
@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodDeclaration methodDeclaration,
|
@NonNull UFunction methodDeclaration,
|
||||||
@NonNull ResolvedMethod method) {
|
@NonNull UFunction superMethod) {
|
||||||
SuperCallVisitor visitor = new SuperCallVisitor(context, method);
|
SuperCallVisitor visitor = new SuperCallVisitor(context, superMethod);
|
||||||
methodDeclaration.accept(visitor);
|
visitor.process(methodDeclaration);
|
||||||
return visitor.mCallsSuper;
|
return visitor.mCallsSuper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SuperCallVisitor(@NonNull JavaContext context, @NonNull ResolvedMethod method) {
|
private SuperCallVisitor(@NonNull UastAndroidContext context, @NonNull UFunction method) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mMethod = method;
|
mMethodFqName = UastUtils.getFqName(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitSuper(Super node) {
|
public boolean visitQualifiedExpression(@NotNull UQualifiedExpression node) {
|
||||||
ResolvedNode resolved = null;
|
UExpression receiver = node.getReceiver();
|
||||||
if (node.getParent() instanceof MethodInvocation) {
|
UExpression selector = node.getSelector();
|
||||||
resolved = mContext.resolve(node.getParent());
|
|
||||||
}
|
if (receiver instanceof USuperExpression && selector instanceof UCallExpression) {
|
||||||
if (resolved == null) {
|
UFunction resolvedFunction = ((UCallExpression) selector).resolve(mContext);
|
||||||
resolved = mContext.resolve(node);
|
if (mMethodFqName.equals(UastUtils.getFqName(resolvedFunction))) {
|
||||||
}
|
mCallsSuper = true;
|
||||||
if (mMethod.equals(resolved)) {
|
return true;
|
||||||
mCallsSuper = true;
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitNode(Node node) {
|
public void process(@NotNull UElement element) {
|
||||||
return mCallsSuper || super.visitNode(node);
|
if (!mCallsSuper) {
|
||||||
|
super.process(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.GRID_VIEW;
|
import static com.android.SdkConstants.GRID_VIEW;
|
||||||
import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
|
import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
|
||||||
@@ -23,15 +23,15 @@ import static com.android.SdkConstants.REQUEST_FOCUS;
|
|||||||
import static com.android.SdkConstants.SCROLL_VIEW;
|
import static com.android.SdkConstants.SCROLL_VIEW;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|||||||
+40
-48
@@ -14,36 +14,31 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
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.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.Expression;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.MethodInvocation;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Node;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.StrictListAccessor;
|
|
||||||
import lombok.ast.StringLiteral;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that Cipher.getInstance is not called with AES as the parameter.
|
* Ensures that Cipher.getInstance is not called with AES as the parameter.
|
||||||
*/
|
*/
|
||||||
public class CipherGetInstanceDetector extends Detector implements Detector.JavaScanner {
|
public class CipherGetInstanceDetector extends Detector implements UastScanner {
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"GetInstance", //$NON-NLS-1$
|
"GetInstance", //$NON-NLS-1$
|
||||||
"Cipher.getInstance with ECB",
|
"Cipher.getInstance with ECB",
|
||||||
@@ -69,59 +64,56 @@ public class CipherGetInstanceDetector extends Detector implements Detector.Java
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getApplicableMethodNames() {
|
public List<String> getApplicableFunctionNames() {
|
||||||
return Collections.singletonList(GET_INSTANCE);
|
return Collections.singletonList(GET_INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation node) {
|
UClass containingClass = UastUtils.getContainingClass(node);
|
||||||
// Ignore if the method doesn't fit our description.
|
if (containingClass == null || !containingClass.isSubclassOf(CIPHER)) {
|
||||||
JavaParser.ResolvedNode resolved = context.resolve(node);
|
|
||||||
if (!(resolved instanceof JavaParser.ResolvedMethod)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
JavaParser.ResolvedMethod method = (JavaParser.ResolvedMethod) resolved;
|
|
||||||
if (!method.getContainingClass().isSubclassOf(CIPHER, false)) {
|
List<UExpression> argumentList = node.getValueArguments();
|
||||||
return;
|
if (argumentList.size() == 1) {
|
||||||
}
|
UExpression expression = argumentList.get(0);
|
||||||
StrictListAccessor<Expression, MethodInvocation> argumentList = node.astArguments();
|
if (expression instanceof ULiteralExpression) {
|
||||||
if (argumentList != null && argumentList.size() == 1) {
|
ULiteralExpression argument = (ULiteralExpression)expression;
|
||||||
Expression expression = argumentList.first();
|
String parameter = argument.getText();
|
||||||
if (expression instanceof StringLiteral) {
|
|
||||||
StringLiteral argument = (StringLiteral)expression;
|
|
||||||
String parameter = argument.astValue();
|
|
||||||
checkParameter(context, node, argument, parameter, false);
|
checkParameter(context, node, argument, parameter, false);
|
||||||
} else {
|
} else if (expression instanceof UResolvable) {
|
||||||
JavaParser.ResolvedNode resolve = context.resolve(expression);
|
UDeclaration declaration = ((UResolvable)expression).resolve(context);
|
||||||
if (resolve instanceof JavaParser.ResolvedField) {
|
if (declaration instanceof UVariable) {
|
||||||
JavaParser.ResolvedField field = (JavaParser.ResolvedField) resolve;
|
UVariable field = (UVariable) declaration;
|
||||||
Object value = field.getValue();
|
UExpression initializer = field.getInitializer();
|
||||||
if (value instanceof String) {
|
if (initializer != null) {
|
||||||
checkParameter(context, node, expression, (String)value, true);
|
Object value = initializer.evaluate();
|
||||||
|
if (value instanceof String) {
|
||||||
|
checkParameter(context, node, expression, (String)value, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkParameter(@NonNull JavaContext context,
|
private static void checkParameter(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation call, @NonNull Node node, @NonNull String value,
|
@NonNull UCallExpression call, @NonNull UExpression arg, @NonNull String value,
|
||||||
boolean includeValue) {
|
boolean includeValue) {
|
||||||
if (ALGORITHM_ONLY.contains(value)) {
|
if (ALGORITHM_ONLY.contains(value)) {
|
||||||
String message = "`Cipher.getInstance` should not be called without setting the"
|
String message = "`Cipher.getInstance` should not be called without setting the"
|
||||||
+ " encryption mode and padding";
|
+ " encryption mode and padding";
|
||||||
context.report(ISSUE, call, context.getLocation(node), message);
|
context.report(ISSUE, call, UastAndroidUtils.getLocation(arg), message);
|
||||||
} else if (value.contains(ECB)) {
|
} else if (value.contains(ECB)) {
|
||||||
String message = "ECB encryption mode should not be used";
|
String message = "ECB encryption mode should not be used";
|
||||||
if (includeValue) {
|
if (includeValue) {
|
||||||
message += " (was \"" + value + "\")";
|
message += " (was \"" + value + "\")";
|
||||||
}
|
}
|
||||||
context.report(ISSUE, call, context.getLocation(node), message);
|
context.report(ISSUE, call, UastAndroidUtils.getLocation(arg), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+189
-200
@@ -14,50 +14,36 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CLASS_CONTEXT;
|
import static com.android.SdkConstants.CLASS_CONTEXT;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedField;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedVariable;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
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.Location;
|
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import lombok.ast.BinaryExpression;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.BinaryOperator;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.ConstructorInvocation;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Expression;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
import lombok.ast.Return;
|
|
||||||
import lombok.ast.StrictListAccessor;
|
|
||||||
import lombok.ast.VariableDefinitionEntry;
|
|
||||||
import lombok.ast.VariableReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for missing {@code recycle} calls on resources that encourage it, and
|
* Checks for missing {@code recycle} calls on resources that encourage it, and
|
||||||
* for missing {@code commit} calls on FragmentTransactions, etc.
|
* for missing {@code commit} calls on FragmentTransactions, etc.
|
||||||
*/
|
*/
|
||||||
public class CleanupDetector extends Detector implements JavaScanner {
|
public class CleanupDetector extends Detector implements UastScanner {
|
||||||
|
|
||||||
private static final Implementation IMPLEMENTATION = new Implementation(
|
private static final Implementation IMPLEMENTATION = new Implementation(
|
||||||
CleanupDetector.class,
|
CleanupDetector.class,
|
||||||
@@ -140,26 +126,26 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
public CleanupDetector() {
|
public CleanupDetector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getApplicableMethodNames() {
|
public List<String> getApplicableFunctionNames() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
// FragmentManager commit check
|
// FragmentManager commit check
|
||||||
BEGIN_TRANSACTION,
|
BEGIN_TRANSACTION,
|
||||||
|
|
||||||
// Recycle check
|
// Recycle check
|
||||||
OBTAIN, OBTAIN_NO_HISTORY,
|
OBTAIN, OBTAIN_NO_HISTORY,
|
||||||
OBTAIN_STYLED_ATTRIBUTES,
|
OBTAIN_STYLED_ATTRIBUTES,
|
||||||
OBTAIN_ATTRIBUTES,
|
OBTAIN_ATTRIBUTES,
|
||||||
OBTAIN_TYPED_ARRAY,
|
OBTAIN_TYPED_ARRAY,
|
||||||
|
|
||||||
// Release check
|
// Release check
|
||||||
ACQUIRE_CPC,
|
ACQUIRE_CPC,
|
||||||
|
|
||||||
// Cursor close check
|
// Cursor close check
|
||||||
QUERY, RAW_QUERY, QUERY_WITH_FACTORY, RAW_QUERY_WITH_FACTORY
|
QUERY, RAW_QUERY, QUERY_WITH_FACTORY, RAW_QUERY_WITH_FACTORY
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,10 +156,8 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation node) {
|
String name = node.getFunctionName();
|
||||||
|
|
||||||
String name = node.astName().astValue();
|
|
||||||
if (BEGIN_TRANSACTION.equals(name)) {
|
if (BEGIN_TRANSACTION.equals(name)) {
|
||||||
checkTransactionCommits(context, node);
|
checkTransactionCommits(context, node);
|
||||||
} else {
|
} else {
|
||||||
@@ -182,48 +166,53 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitConstructor(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitConstructor(UastAndroidContext context, UCallExpression functionCall, UFunction constructor) {
|
||||||
@NonNull ConstructorInvocation node, @NonNull ResolvedMethod constructor) {
|
UClass containingClass = UastUtils.getContainingClass(constructor);
|
||||||
checkRecycled(context, node, constructor.getContainingClass().getSignature(), RELEASE);
|
if (containingClass != null) {
|
||||||
|
checkRecycled(context, functionCall, containingClass.getFqName(), RELEASE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkResourceRecycled(@NonNull JavaContext context,
|
private static void checkResourceRecycled(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation node, @NonNull String name) {
|
@NonNull UCallExpression node, @NonNull String name) {
|
||||||
// Recycle detector
|
// Recycle detector
|
||||||
ResolvedNode resolved = context.resolve(node);
|
UFunction method = node.resolve(context);
|
||||||
if (!(resolved instanceof ResolvedMethod)) {
|
if (method == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
UClass containingClass = UastUtils.getContainingClass(method);
|
||||||
ResolvedClass containingClass = method.getContainingClass();
|
if (containingClass == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((OBTAIN.equals(name) || OBTAIN_NO_HISTORY.equals(name)) &&
|
if ((OBTAIN.equals(name) || OBTAIN_NO_HISTORY.equals(name)) &&
|
||||||
containingClass.isSubclassOf(MOTION_EVENT_CLS, false)) {
|
containingClass.isSubclassOf(MOTION_EVENT_CLS)) {
|
||||||
checkRecycled(context, node, MOTION_EVENT_CLS, RECYCLE);
|
checkRecycled(context, node, MOTION_EVENT_CLS, RECYCLE);
|
||||||
} else if (OBTAIN.equals(name) && containingClass.isSubclassOf(PARCEL_CLS, false)) {
|
} else if (OBTAIN.equals(name) && containingClass.isSubclassOf(PARCEL_CLS)) {
|
||||||
checkRecycled(context, node, PARCEL_CLS, RECYCLE);
|
checkRecycled(context, node, PARCEL_CLS, RECYCLE);
|
||||||
} else if (OBTAIN.equals(name) &&
|
} else if (OBTAIN.equals(name) &&
|
||||||
containingClass.isSubclassOf(VELOCITY_TRACKER_CLS, false)) {
|
containingClass.isSubclassOf(VELOCITY_TRACKER_CLS)) {
|
||||||
checkRecycled(context, node, VELOCITY_TRACKER_CLS, RECYCLE);
|
checkRecycled(context, node, VELOCITY_TRACKER_CLS, RECYCLE);
|
||||||
} else if ((OBTAIN_STYLED_ATTRIBUTES.equals(name)
|
} else if ((OBTAIN_STYLED_ATTRIBUTES.equals(name)
|
||||||
|| OBTAIN_ATTRIBUTES.equals(name)
|
|| OBTAIN_ATTRIBUTES.equals(name)
|
||||||
|| OBTAIN_TYPED_ARRAY.equals(name)) &&
|
|| OBTAIN_TYPED_ARRAY.equals(name)) &&
|
||||||
(containingClass.isSubclassOf(CLASS_CONTEXT, false) ||
|
(containingClass.isSubclassOf(CLASS_CONTEXT) ||
|
||||||
containingClass.isSubclassOf(RESOURCES_CLS, false))) {
|
containingClass.isSubclassOf(RESOURCES_CLS))) {
|
||||||
TypeDescriptor returnType = method.getReturnType();
|
UType returnType = method.getReturnType();
|
||||||
if (returnType != null && returnType.matchesSignature(TYPED_ARRAY_CLS)) {
|
if (returnType != null && returnType.matchesFqName(TYPED_ARRAY_CLS)) {
|
||||||
checkRecycled(context, node, TYPED_ARRAY_CLS, RECYCLE);
|
checkRecycled(context, node, TYPED_ARRAY_CLS, RECYCLE);
|
||||||
}
|
}
|
||||||
} else if (ACQUIRE_CPC.equals(name) && containingClass.isSubclassOf(
|
} else if (ACQUIRE_CPC.equals(name) && containingClass.isSubclassOf(
|
||||||
CONTENT_RESOLVER_CLS, false)) {
|
CONTENT_RESOLVER_CLS)) {
|
||||||
checkRecycled(context, node, CONTENT_PROVIDER_CLIENT_CLS, RELEASE);
|
checkRecycled(context, node, CONTENT_PROVIDER_CLIENT_CLS, RELEASE);
|
||||||
} else if ((QUERY.equals(name)
|
} else if ((QUERY.equals(name)
|
||||||
|| RAW_QUERY.equals(name)
|
|| RAW_QUERY.equals(name)
|
||||||
|| QUERY_WITH_FACTORY.equals(name)
|
|| QUERY_WITH_FACTORY.equals(name)
|
||||||
|| RAW_QUERY_WITH_FACTORY.equals(name))
|
|| RAW_QUERY_WITH_FACTORY.equals(name))
|
||||||
&& (containingClass.isSubclassOf(SQLITE_DATABASE_CLS, false) ||
|
&& (containingClass.isSubclassOf(SQLITE_DATABASE_CLS) ||
|
||||||
containingClass.isSubclassOf(CONTENT_RESOLVER_CLS, false) ||
|
containingClass.isSubclassOf(CONTENT_RESOLVER_CLS) ||
|
||||||
containingClass.isSubclassOf(CONTENT_PROVIDER_CLS, false) ||
|
containingClass.isSubclassOf(CONTENT_PROVIDER_CLS) ||
|
||||||
containingClass.isSubclassOf(CONTENT_PROVIDER_CLIENT_CLS, false))) {
|
containingClass.isSubclassOf(CONTENT_PROVIDER_CLIENT_CLS))) {
|
||||||
// Other potential cursors-returning methods that should be tracked:
|
// Other potential cursors-returning methods that should be tracked:
|
||||||
// android.app.DownloadManager#query
|
// android.app.DownloadManager#query
|
||||||
// android.content.ContentProviderClient#query
|
// android.content.ContentProviderClient#query
|
||||||
@@ -242,34 +231,35 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkRecycled(@NonNull final JavaContext context, @NonNull Node node,
|
private static void checkRecycled(@NonNull final UastAndroidContext context, @NonNull UElement node,
|
||||||
@NonNull final String recycleType, @NonNull final String recycleName) {
|
@NonNull final String recycleType, @NonNull final String recycleName) {
|
||||||
ResolvedVariable boundVariable = getVariable(context, node);
|
UVariable boundVariable = getVariable(context, node);
|
||||||
if (boundVariable == null) {
|
if (boundVariable == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node method = JavaContext.findSurroundingMethod(node);
|
UFunction method = UastUtils.getContainingFunction(node);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FinishVisitor visitor = new FinishVisitor(context, boundVariable) {
|
FinishVisitor visitor = new FinishVisitor(context, boundVariable) {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isCleanupCall(@NonNull MethodInvocation call) {
|
protected boolean isCleanupCall(@NonNull UCallExpression call) {
|
||||||
String methodName = call.astName().astValue();
|
String methodName = call.getFunctionName();
|
||||||
if (!recycleName.equals(methodName)) {
|
if (!recycleName.equals(methodName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ResolvedNode resolved = mContext.resolve(call);
|
UDeclaration resolved = call.resolve(mContext);
|
||||||
if (resolved instanceof ResolvedMethod) {
|
if (resolved != null) {
|
||||||
ResolvedClass containingClass = ((ResolvedMethod) resolved).getContainingClass();
|
UClass containingClass = UastUtils.getContainingClassOrEmpty(resolved);
|
||||||
if (containingClass.isSubclassOf(recycleType, false)) {
|
if (containingClass.isSubclassOf(recycleType)) {
|
||||||
// Yes, called the right recycle() method; now make sure
|
// Yes, called the right recycle() method; now make sure
|
||||||
// we're calling it on the right variable
|
// we're calling it on the right variable
|
||||||
Expression operand = call.astOperand();
|
UElement parent = call.getParent();
|
||||||
if (operand != null) {
|
if (parent instanceof UQualifiedExpression) {
|
||||||
resolved = mContext.resolve(operand);
|
UExpression operand = ((UQualifiedExpression) parent).getReceiver();
|
||||||
|
resolved = UastUtils.resolveIfCan(operand, mContext);
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
if (resolved != null && mVariables.contains(resolved)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -281,7 +271,7 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
method.accept(visitor);
|
visitor.process(method);
|
||||||
if (visitor.isCleanedUp() || visitor.variableEscapes()) {
|
if (visitor.isCleanedUp() || visitor.variableEscapes()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -296,46 +286,46 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
"This `%1$s` should be freed up after use with `#%2$s()`", className,
|
"This `%1$s` should be freed up after use with `#%2$s()`", className,
|
||||||
recycleName);
|
recycleName);
|
||||||
}
|
}
|
||||||
Node locationNode = node instanceof MethodInvocation ?
|
UElement locationNode = node instanceof UCallExpression ?
|
||||||
((MethodInvocation) node).astName() : node;
|
((UCallExpression) node).getFunctionNameElement() : node;
|
||||||
Location location = context.getLocation(locationNode);
|
Location location = UastAndroidUtils.getLocation(locationNode);
|
||||||
context.report(RECYCLE_RESOURCE, node, location, message);
|
context.report(RECYCLE_RESOURCE, node, location, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkTransactionCommits(@NonNull JavaContext context,
|
private static boolean checkTransactionCommits(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation node) {
|
@NonNull UCallExpression node) {
|
||||||
if (isBeginTransaction(context, node)) {
|
if (isBeginTransaction(context, node)) {
|
||||||
ResolvedVariable boundVariable = getVariable(context, node);
|
UVariable boundVariable = getVariable(context, node);
|
||||||
if (boundVariable == null && isCommittedInChainedCalls(context, node)) {
|
if (boundVariable == null && isCommittedInChainedCalls(context, node)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boundVariable != null) {
|
if (boundVariable != null) {
|
||||||
Node method = JavaContext.findSurroundingMethod(node);
|
UFunction method = UastUtils.getContainingFunction(node);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FinishVisitor commitVisitor = new FinishVisitor(context, boundVariable) {
|
FinishVisitor commitVisitor = new FinishVisitor(context, boundVariable) {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isCleanupCall(@NonNull MethodInvocation call) {
|
protected boolean isCleanupCall(@NonNull UCallExpression call) {
|
||||||
if (isTransactionCommitMethodCall(mContext, call)) {
|
if (isTransactionCommitMethodCall(mContext, call)) {
|
||||||
Expression operand = call.astOperand();
|
UExpression operand = UastUtils.getReceiver(call);
|
||||||
if (operand != null) {
|
if (operand instanceof UResolvable) {
|
||||||
ResolvedNode resolved = mContext.resolve(operand);
|
UDeclaration resolved = ((UResolvable) operand).resolve(mContext);
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
if (resolved != null && mVariables.contains(resolved)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (resolved instanceof ResolvedMethod
|
} else if (resolved instanceof UFunction
|
||||||
&& operand instanceof MethodInvocation
|
&& operand instanceof UCallExpression
|
||||||
&& isCommittedInChainedCalls(mContext,(MethodInvocation) operand)) {
|
&& isCommittedInChainedCalls(mContext, (UCallExpression) operand)) {
|
||||||
// Check that the target of the committed chains is the
|
// Check that the target of the committed chains is the
|
||||||
// right variable!
|
// right variable!
|
||||||
while (operand instanceof MethodInvocation) {
|
while (operand instanceof UCallExpression) {
|
||||||
operand = ((MethodInvocation)operand).astOperand();
|
operand = UastUtils.getReceiver((UCallExpression)operand);
|
||||||
}
|
}
|
||||||
if (operand instanceof VariableReference) {
|
if (operand instanceof USimpleReferenceExpression) {
|
||||||
resolved = mContext.resolve(operand);
|
resolved = ((USimpleReferenceExpression)operand).resolve(mContext);
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
if (resolved != null && mVariables.contains(resolved)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -344,11 +334,10 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (isShowFragmentMethodCall(mContext, call)) {
|
} else if (isShowFragmentMethodCall(mContext, call)) {
|
||||||
StrictListAccessor<Expression, MethodInvocation> arguments =
|
List<UExpression> arguments = call.getValueArguments();
|
||||||
call.astArguments();
|
|
||||||
if (arguments.size() == 2) {
|
if (arguments.size() == 2) {
|
||||||
Expression first = arguments.first();
|
UExpression first = arguments.get(0);
|
||||||
ResolvedNode resolved = mContext.resolve(first);
|
UDeclaration resolved = UastUtils.resolveIfCan(first, mContext);
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
if (resolved != null && mVariables.contains(resolved)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -359,29 +348,29 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
method.accept(commitVisitor);
|
commitVisitor.handle(method);
|
||||||
if (commitVisitor.isCleanedUp() || commitVisitor.variableEscapes()) {
|
if (commitVisitor.isCleanedUp() || commitVisitor.variableEscapes()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String message = "This transaction should be completed with a `commit()` call";
|
String message = "This transaction should be completed with a `commit()` call";
|
||||||
context.report(COMMIT_FRAGMENT, node, context.getLocation(node.astName()),
|
context.report(COMMIT_FRAGMENT, node, UastAndroidUtils.getLocation(node.getFunctionReference()),
|
||||||
message);
|
message);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isCommittedInChainedCalls(@NonNull JavaContext context,
|
private static boolean isCommittedInChainedCalls(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation node) {
|
@NonNull UCallExpression node) {
|
||||||
// Look for chained calls since the FragmentManager methods all return "this"
|
// Look for chained calls since the FragmentManager methods all return "this"
|
||||||
// to allow constructor chaining, e.g.
|
// to allow constructor chaining, e.g.
|
||||||
// getFragmentManager().beginTransaction().addToBackStack("test")
|
// getFragmentManager().beginTransaction().addToBackStack("test")
|
||||||
// .disallowAddToBackStack().hide(mFragment2).setBreadCrumbShortTitle("test")
|
// .disallowAddToBackStack().hide(mFragment2).setBreadCrumbShortTitle("test")
|
||||||
// .show(mFragment2).setCustomAnimations(0, 0).commit();
|
// .show(mFragment2).setCustomAnimations(0, 0).commit();
|
||||||
Node parent = node.getParent();
|
UElement parent = node.getParent();
|
||||||
while (parent instanceof MethodInvocation) {
|
while (parent instanceof UCallExpression) {
|
||||||
MethodInvocation methodInvocation = (MethodInvocation) parent;
|
UCallExpression methodInvocation = (UCallExpression) parent;
|
||||||
if (isTransactionCommitMethodCall(context, methodInvocation)
|
if (isTransactionCommitMethodCall(context, methodInvocation)
|
||||||
|| isShowFragmentMethodCall(context, methodInvocation)) {
|
|| isShowFragmentMethodCall(context, methodInvocation)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -393,74 +382,71 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isTransactionCommitMethodCall(@NonNull JavaContext context,
|
private static boolean isTransactionCommitMethodCall(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation call) {
|
@NonNull UCallExpression call) {
|
||||||
|
|
||||||
String methodName = call.astName().astValue();
|
String methodName = call.getFunctionName();
|
||||||
return (COMMIT.equals(methodName) || COMMIT_ALLOWING_LOSS.equals(methodName)) &&
|
return (COMMIT.equals(methodName) || COMMIT_ALLOWING_LOSS.equals(methodName)) &&
|
||||||
isMethodOnFragmentClass(context, call,
|
isMethodOnFragmentClass(context, call,
|
||||||
FRAGMENT_TRANSACTION_CLS,
|
FRAGMENT_TRANSACTION_CLS,
|
||||||
FRAGMENT_TRANSACTION_V4_CLS);
|
FRAGMENT_TRANSACTION_V4_CLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isShowFragmentMethodCall(@NonNull JavaContext context,
|
private static boolean isShowFragmentMethodCall(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation call) {
|
@NonNull UCallExpression call) {
|
||||||
String methodName = call.astName().astValue();
|
String methodName = call.getFunctionName();
|
||||||
return SHOW.equals(methodName)
|
return SHOW.equals(methodName)
|
||||||
&& isMethodOnFragmentClass(context, call,
|
&& isMethodOnFragmentClass(context, call,
|
||||||
DIALOG_FRAGMENT, DIALOG_V4_FRAGMENT);
|
DIALOG_FRAGMENT, DIALOG_V4_FRAGMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isMethodOnFragmentClass(
|
private static boolean isMethodOnFragmentClass(
|
||||||
@NonNull JavaContext context,
|
@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation call,
|
@NonNull UCallExpression call,
|
||||||
@NonNull String fragmentClass,
|
@NonNull String fragmentClass,
|
||||||
@NonNull String v4FragmentClass) {
|
@NonNull String v4FragmentClass) {
|
||||||
ResolvedNode resolved = context.resolve(call);
|
UFunction resolved = call.resolve(context);
|
||||||
if (resolved instanceof ResolvedMethod) {
|
if (resolved != null) {
|
||||||
ResolvedClass containingClass = ((ResolvedMethod) resolved).getContainingClass();
|
UClass containingClass = UastUtils.getContainingClassOrEmpty(resolved);
|
||||||
return containingClass.isSubclassOf(fragmentClass, false) ||
|
return containingClass.isSubclassOf(fragmentClass) ||
|
||||||
containingClass.isSubclassOf(v4FragmentClass, false);
|
containingClass.isSubclassOf(v4FragmentClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static ResolvedVariable getVariable(@NonNull JavaContext context,
|
public static UVariable getVariable(@NonNull UastAndroidContext context,
|
||||||
@NonNull Node expression) {
|
@NonNull UElement expression) {
|
||||||
Node parent = expression.getParent();
|
UElement parent = expression.getParent();
|
||||||
if (parent instanceof BinaryExpression) {
|
if (parent instanceof UBinaryExpression) {
|
||||||
BinaryExpression binaryExpression = (BinaryExpression) parent;
|
UBinaryExpression binaryExpression = (UBinaryExpression) parent;
|
||||||
if (binaryExpression.astOperator() == BinaryOperator.ASSIGN) {
|
if (binaryExpression.getOperator() == UastBinaryOperator.ASSIGN) {
|
||||||
Expression lhs = binaryExpression.astLeft();
|
UExpression lhs = binaryExpression.getLeftOperand();
|
||||||
ResolvedNode resolved = context.resolve(lhs);
|
if (lhs instanceof UResolvable) {
|
||||||
if (resolved instanceof ResolvedVariable) {
|
UDeclaration resolved = ((UResolvable) lhs).resolve(context);
|
||||||
return (ResolvedVariable) resolved;
|
if (resolved instanceof UVariable) {
|
||||||
|
return (UVariable) resolved;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (parent instanceof VariableDefinitionEntry) {
|
} else if (parent instanceof UVariable) {
|
||||||
ResolvedNode resolved = context.resolve(parent);
|
return (UVariable) parent;
|
||||||
if (resolved instanceof ResolvedVariable) {
|
|
||||||
return (ResolvedVariable) resolved;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isBeginTransaction(@NonNull JavaContext context,
|
private static boolean isBeginTransaction(@NonNull UastAndroidContext context,
|
||||||
@NonNull MethodInvocation node) {
|
@NonNull UCallExpression node) {
|
||||||
String methodName = node.astName().astValue();
|
String methodName = node.getFunctionName();
|
||||||
assert methodName.equals(BEGIN_TRANSACTION) : methodName;
|
assert BEGIN_TRANSACTION.equals(methodName) : methodName;
|
||||||
if (BEGIN_TRANSACTION.equals(methodName)) {
|
if (BEGIN_TRANSACTION.equals(methodName)) {
|
||||||
ResolvedNode resolved = context.resolve(node);
|
UFunction method = node.resolve(context);
|
||||||
if (resolved instanceof ResolvedMethod) {
|
if (method != null) {
|
||||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
UClass containingClass = UastUtils.getContainingClassOrEmpty(method);
|
||||||
ResolvedClass containingClass = method.getContainingClass();
|
if (containingClass.isSubclassOf(FRAGMENT_MANAGER_CLS)
|
||||||
if (containingClass.isSubclassOf(FRAGMENT_MANAGER_CLS, false)
|
|| containingClass.isSubclassOf(FRAGMENT_MANAGER_V4_CLS)) {
|
||||||
|| containingClass.isSubclassOf(FRAGMENT_MANAGER_V4_CLS,
|
|
||||||
false)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -475,13 +461,13 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
* case of a TypedArray we're looking for a "recycle", call, in the
|
* case of a TypedArray we're looking for a "recycle", call, in the
|
||||||
* case of a database cursor we're looking for a "close" call, etc.
|
* case of a database cursor we're looking for a "close" call, etc.
|
||||||
*/
|
*/
|
||||||
private abstract static class FinishVisitor extends ForwardingAstVisitor {
|
private abstract static class FinishVisitor extends UastVisitor {
|
||||||
protected final JavaContext mContext;
|
protected final UastAndroidContext mContext;
|
||||||
protected final List<ResolvedVariable> mVariables;
|
protected final List<UVariable> mVariables;
|
||||||
private boolean mContainsCleanup;
|
private boolean mContainsCleanup;
|
||||||
private boolean mEscapes;
|
private boolean mEscapes;
|
||||||
|
|
||||||
public FinishVisitor(JavaContext context, @NonNull ResolvedVariable variable) {
|
public FinishVisitor(UastAndroidContext context, @NonNull UVariable variable) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mVariables = Lists.newArrayList(variable);
|
mVariables = Lists.newArrayList(variable);
|
||||||
}
|
}
|
||||||
@@ -495,25 +481,25 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitNode(Node node) {
|
public void process(@NotNull UElement element) {
|
||||||
return mContainsCleanup || super.visitNode(node);
|
if (!mContainsCleanup) {
|
||||||
|
super.process(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean isCleanupCall(@NonNull MethodInvocation call);
|
protected abstract boolean isCleanupCall(@NonNull UCallExpression call);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitMethodInvocation(MethodInvocation call) {
|
public boolean visitCallExpression(@NotNull UCallExpression call) {
|
||||||
if (mContainsCleanup) {
|
if (mContainsCleanup) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitMethodInvocation(call);
|
|
||||||
|
|
||||||
// Look for escapes
|
// Look for escapes
|
||||||
if (!mEscapes) {
|
if (!mEscapes) {
|
||||||
for (Expression expression : call.astArguments()) {
|
for (UExpression expression : call.getValueArguments()) {
|
||||||
if (expression instanceof VariableReference) {
|
if (expression instanceof USimpleReferenceExpression) {
|
||||||
ResolvedNode resolved = mContext.resolve(expression);
|
UDeclaration resolved = ((USimpleReferenceExpression) expression).resolve(mContext);
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
if (resolved != null && mVariables.contains(resolved)) {
|
||||||
mEscapes = true;
|
mEscapes = true;
|
||||||
@@ -521,12 +507,11 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
// Special case: MotionEvent.obtain(MotionEvent): passing in an
|
// Special case: MotionEvent.obtain(MotionEvent): passing in an
|
||||||
// event here does not recycle the event, and we also know it
|
// event here does not recycle the event, and we also know it
|
||||||
// doesn't escape
|
// doesn't escape
|
||||||
if (OBTAIN.equals(call.astName().astValue())) {
|
if (OBTAIN.equals(call.getFunctionName())) {
|
||||||
ResolvedNode r = mContext.resolve(call);
|
UFunction method = call.resolve(mContext);
|
||||||
if (r instanceof ResolvedMethod) {
|
if (method != null) {
|
||||||
ResolvedMethod method = (ResolvedMethod) r;
|
UClass cls = UastUtils.getContainingClassOrEmpty(method);
|
||||||
ResolvedClass cls = method.getContainingClass();
|
if (cls.matchesFqName(MOTION_EVENT_CLS)) {
|
||||||
if (cls.matches(MOTION_EVENT_CLS)) {
|
|
||||||
mEscapes = false;
|
mEscapes = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -545,57 +530,61 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) {
|
public boolean visitVariable(@NotNull UVariable node) {
|
||||||
Expression initializer = node.astInitializer();
|
UExpression initializer = node.getInitializer();
|
||||||
if (initializer instanceof VariableReference) {
|
if (initializer instanceof USimpleReferenceExpression) {
|
||||||
ResolvedNode resolved = mContext.resolve(initializer);
|
UDeclaration resolved = ((USimpleReferenceExpression) initializer).resolve(mContext);
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
if (resolved != null && mVariables.contains(resolved)) {
|
||||||
ResolvedNode resolvedVariable = mContext.resolve(node);
|
if (node.getKind() == UastVariableKind.LOCAL_VARIABLE) {
|
||||||
if (resolvedVariable instanceof ResolvedVariable) {
|
mVariables.add(node);
|
||||||
ResolvedVariable variable = (ResolvedVariable) resolvedVariable;
|
} else if (node.getKind() == UastVariableKind.MEMBER) {
|
||||||
mVariables.add(variable);
|
|
||||||
} else if (resolvedVariable instanceof ResolvedField) {
|
|
||||||
mEscapes = true;
|
mEscapes = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.visitVariableDefinitionEntry(node);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitBinaryExpression(BinaryExpression node) {
|
public boolean visitBinaryExpression(@NotNull UBinaryExpression node) {
|
||||||
if (node.astOperator() == BinaryOperator.ASSIGN) {
|
if (node.getOperator() == UastBinaryOperator.ASSIGN) {
|
||||||
Expression rhs = node.astRight();
|
UExpression rhs = node.getRightOperand();
|
||||||
if (rhs instanceof VariableReference) {
|
if (rhs instanceof USimpleReferenceExpression) {
|
||||||
ResolvedNode resolved = mContext.resolve(rhs);
|
UDeclaration resolved = ((USimpleReferenceExpression) rhs).resolve(mContext);
|
||||||
|
UExpression leftOperand = node.getLeftOperand();
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
if (resolved != null && mVariables.contains(resolved) && leftOperand instanceof UResolvable) {
|
||||||
ResolvedNode resolvedLhs = mContext.resolve(node.astLeft());
|
UDeclaration resolvedLhs = ((UResolvable) leftOperand).resolve(mContext);
|
||||||
if (resolvedLhs instanceof ResolvedVariable) {
|
if (resolvedLhs instanceof UVariable) {
|
||||||
ResolvedVariable variable = (ResolvedVariable) resolvedLhs;
|
UVariable variable = (UVariable) resolvedLhs;
|
||||||
mVariables.add(variable);
|
if (variable.getKind() == UastVariableKind.LOCAL_VARIABLE) {
|
||||||
} else if (resolvedLhs instanceof ResolvedField) {
|
mVariables.add(variable);
|
||||||
mEscapes = true;
|
} else if (variable.getKind() == UastVariableKind.MEMBER) {
|
||||||
|
mEscapes = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.visitBinaryExpression(node);
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitReturn(Return node) {
|
public boolean visitSpecialExpressionList(@NotNull USpecialExpressionList node) {
|
||||||
Expression value = node.astValue();
|
if (node.getKind() == UastSpecialExpressionKind.RETURN) {
|
||||||
if (value instanceof VariableReference) {
|
UExpression value = node.firstOrNull();
|
||||||
ResolvedNode resolved = mContext.resolve(value);
|
if (value instanceof USimpleReferenceExpression) {
|
||||||
//noinspection SuspiciousMethodCalls
|
UDeclaration resolved = ((USimpleReferenceExpression) value).resolve(mContext);
|
||||||
if (resolved != null && mVariables.contains(resolved)) {
|
//noinspection SuspiciousMethodCalls
|
||||||
mEscapes = true;
|
if (resolved != null && mVariables.contains(resolved)) {
|
||||||
|
mEscapes = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.visitReturn(node);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -14,20 +14,20 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_VIEW_VIEW;
|
import static com.android.SdkConstants.ANDROID_VIEW_VIEW;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.ClassContext;
|
import com.android.tools.klint.detector.api.ClassContext;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
|||||||
@@ -14,33 +14,26 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.Comment;
|
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for issues in Java comments
|
* Looks for issues in Java comments
|
||||||
*/
|
*/
|
||||||
public class CommentDetector extends Detector implements Detector.JavaScanner {
|
public class CommentDetector extends Detector implements UastScanner {
|
||||||
private static final String STOPSHIP_COMMENT = "STOPSHIP"; //$NON-NLS-1$
|
private static final String STOPSHIP_COMMENT = "STOPSHIP"; //$NON-NLS-1$
|
||||||
|
|
||||||
private static final Implementation IMPLEMENTATION = new Implementation(
|
private static final Implementation IMPLEMENTATION = new Implementation(
|
||||||
@@ -96,7 +89,7 @@ public class CommentDetector extends Detector implements Detector.JavaScanner {
|
|||||||
return Speed.NORMAL;
|
return Speed.NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/*@Override
|
||||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
||||||
if (USE_AST) {
|
if (USE_AST) {
|
||||||
return Collections.<Class<? extends Node>>singletonList(Comment.class);
|
return Collections.<Class<? extends Node>>singletonList(Comment.class);
|
||||||
@@ -135,7 +128,7 @@ public class CommentDetector extends Detector implements Detector.JavaScanner {
|
|||||||
} else if (next == '*') {
|
} else if (next == '*') {
|
||||||
// Block comment
|
// Block comment
|
||||||
int start = i + 2;
|
int start = i + 2;
|
||||||
int end = source.indexOf("*/", start);
|
int end = source.indexOf("*//*", start);
|
||||||
if (end == -1) {
|
if (end == -1) {
|
||||||
end = n;
|
end = n;
|
||||||
}
|
}
|
||||||
@@ -195,5 +188,5 @@ public class CommentDetector extends Detector implements Detector.JavaScanner {
|
|||||||
"to release");
|
"to release");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
|
|||||||
+49
-59
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CLASS_VIEW;
|
import static com.android.SdkConstants.CLASS_VIEW;
|
||||||
import static com.android.SdkConstants.CLASS_VIEWGROUP;
|
import static com.android.SdkConstants.CLASS_VIEWGROUP;
|
||||||
@@ -22,36 +22,29 @@ import static com.android.SdkConstants.DOT_LAYOUT_PARAMS;
|
|||||||
import static com.android.SdkConstants.R_STYLEABLE_PREFIX;
|
import static com.android.SdkConstants.R_STYLEABLE_PREFIX;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
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 com.google.common.collect.Iterators;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.ClassDeclaration;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Expression;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.ExpressionStatement;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.StrictListAccessor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure that custom views use a declare styleable that matches
|
* Makes sure that custom views use a declare styleable that matches
|
||||||
* the name of the custom view
|
* the name of the custom view
|
||||||
*/
|
*/
|
||||||
public class CustomViewDetector extends Detector implements Detector.JavaScanner {
|
public class CustomViewDetector extends Detector implements UastScanner {
|
||||||
|
|
||||||
private static final Implementation IMPLEMENTATION = new Implementation(
|
private static final Implementation IMPLEMENTATION = new Implementation(
|
||||||
CustomViewDetector.class,
|
CustomViewDetector.class,
|
||||||
@@ -76,7 +69,7 @@ public class CustomViewDetector extends Detector implements Detector.JavaScanner
|
|||||||
|
|
||||||
private static final String OBTAIN_STYLED_ATTRIBUTES = "obtainStyledAttributes"; //$NON-NLS-1$
|
private static final String OBTAIN_STYLED_ATTRIBUTES = "obtainStyledAttributes"; //$NON-NLS-1$
|
||||||
|
|
||||||
/** Constructs a new {@link com.android.tools.lint.checks.CustomViewDetector} check */
|
/** Constructs a new {@link CustomViewDetector} check */
|
||||||
public CustomViewDetector() {
|
public CustomViewDetector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,79 +84,76 @@ public class CustomViewDetector extends Detector implements Detector.JavaScanner
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getApplicableMethodNames() {
|
public List<String> getApplicableFunctionNames() {
|
||||||
return Collections.singletonList(OBTAIN_STYLED_ATTRIBUTES);
|
return Collections.singletonList(OBTAIN_STYLED_ATTRIBUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation node) {
|
if (node.getParent() instanceof UExpression) {
|
||||||
if (node.getParent() instanceof ExpressionStatement) {
|
if (!context.getLintContext().isContextMethod(node)) {
|
||||||
if (!context.isContextMethod(node)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StrictListAccessor<Expression, MethodInvocation> expressions = node.astArguments();
|
List<UExpression> expressions = node.getValueArguments();
|
||||||
int size = expressions.size();
|
int size = expressions.size();
|
||||||
// Which parameter contains the styleable (attrs) ?
|
// Which parameter contains the styleable (attrs) ?
|
||||||
int parameterIndex;
|
int parameterIndex;
|
||||||
if (size == 1) {
|
if (size == 1) {
|
||||||
// obtainStyledAttributes(int[] attrs)
|
// obtainStyledAttributes(int[] attrs)
|
||||||
parameterIndex = 0;
|
parameterIndex = 0;
|
||||||
} else {
|
} else if (size > 1) {
|
||||||
// obtainStyledAttributes(int resid, int[] attrs)
|
// obtainStyledAttributes(int resid, int[] attrs)
|
||||||
// obtainStyledAttributes(AttributeSet set, int[] attrs)
|
// obtainStyledAttributes(AttributeSet set, int[] attrs)
|
||||||
// obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
|
// obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
|
||||||
parameterIndex = 1;
|
parameterIndex = 1;
|
||||||
}
|
} else {
|
||||||
Expression expression = Iterators.get(node.astArguments().iterator(), parameterIndex,
|
|
||||||
null);
|
|
||||||
if (expression == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String s = expression.toString();
|
|
||||||
|
UExpression expression = expressions.get(parameterIndex);
|
||||||
|
if (!(expression instanceof UQualifiedExpression)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String s = expression.renderString();
|
||||||
if (!s.startsWith(R_STYLEABLE_PREFIX)) {
|
if (!s.startsWith(R_STYLEABLE_PREFIX)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String styleableName = s.substring(R_STYLEABLE_PREFIX.length());
|
String styleableName = s.substring(R_STYLEABLE_PREFIX.length());
|
||||||
ClassDeclaration cls = JavaContext.findSurroundingClass(node);
|
|
||||||
if (cls == null) {
|
UClass resolvedClass = UastUtils.getContainingClass(node);
|
||||||
|
if (resolvedClass == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedNode resolved = context.resolve(cls);
|
String className = resolvedClass.getName();
|
||||||
if (!(resolved instanceof ResolvedClass)) {
|
if (resolvedClass.isSubclassOf(CLASS_VIEW)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String className = cls.astName().astValue();
|
|
||||||
ResolvedClass resolvedClass = (ResolvedClass) resolved;
|
|
||||||
if (resolvedClass.isSubclassOf(CLASS_VIEW, false)) {
|
|
||||||
if (!styleableName.equals(className)) {
|
if (!styleableName.equals(className)) {
|
||||||
String message = String.format(
|
String message = String.format(
|
||||||
"By convention, the custom view (`%1$s`) and the declare-styleable (`%2$s`) "
|
"By convention, the custom view (`%1$s`) and the declare-styleable (`%2$s`) "
|
||||||
+ "should have the same name (various editor features rely on "
|
+ "should have the same name (various editor features rely on "
|
||||||
+ "this convention)",
|
+ "this convention)",
|
||||||
className, styleableName);
|
className, styleableName);
|
||||||
context.report(ISSUE, node, context.getLocation(expression), message);
|
context.report(ISSUE, node, UastAndroidUtils.getLocation(expression), message);
|
||||||
}
|
}
|
||||||
} else if (resolvedClass.isSubclassOf(CLASS_VIEWGROUP + DOT_LAYOUT_PARAMS, false)) {
|
} else if (resolvedClass.isSubclassOf(CLASS_VIEWGROUP + DOT_LAYOUT_PARAMS)) {
|
||||||
ClassDeclaration outer = JavaContext.findSurroundingClass(cls.getParent());
|
UClass outer = UastUtils.getContainingClass(resolvedClass);
|
||||||
if (outer == null) {
|
if (outer == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String layoutClassName = outer.astName().astValue();
|
String layoutClassName = outer.getName();
|
||||||
String expectedName = layoutClassName + "_Layout";
|
String expectedName = layoutClassName + "_Layout";
|
||||||
if (!styleableName.equals(expectedName)) {
|
if (!styleableName.equals(expectedName)) {
|
||||||
String message = String.format(
|
String message = String.format(
|
||||||
"By convention, the declare-styleable (`%1$s`) for a layout parameter "
|
"By convention, the declare-styleable (`%1$s`) for a layout parameter "
|
||||||
+ "class (`%2$s`) is expected to be the surrounding "
|
+ "class (`%2$s`) is expected to be the surrounding "
|
||||||
+ "class (`%3$s`) plus \"`_Layout`\", e.g. `%4$s`. "
|
+ "class (`%3$s`) plus \"`_Layout`\", e.g. `%4$s`. "
|
||||||
+ "(Various editor features rely on this convention.)",
|
+ "(Various editor features rely on this convention.)",
|
||||||
styleableName, className, layoutClassName, expectedName);
|
styleableName, className, layoutClassName, expectedName);
|
||||||
context.report(ISSUE, node, context.getLocation(expression), message);
|
context.report(ISSUE, node, UastAndroidUtils.getLocation(expression), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,21 +14,20 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.RESOURCE_CLZ_ID;
|
import static com.android.SdkConstants.RESOURCE_CLZ_ID;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -36,24 +35,17 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import lombok.ast.ArrayAccess;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.BinaryExpression;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.Cast;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Expression;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
import lombok.ast.If;
|
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
import lombok.ast.Select;
|
|
||||||
import lombok.ast.Statement;
|
|
||||||
import lombok.ast.VariableDefinitionEntry;
|
|
||||||
import lombok.ast.VariableReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detector looking for cut & paste issues
|
* Detector looking for cut & paste issues
|
||||||
*/
|
*/
|
||||||
public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
public class CutPasteDetector extends Detector implements UastScanner {
|
||||||
/** The main issue discovered by this detector */
|
/** The main issue discovered by this detector */
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"CutPasteId", //$NON-NLS-1$
|
"CutPasteId", //$NON-NLS-1$
|
||||||
@@ -73,8 +65,8 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
|||||||
CutPasteDetector.class,
|
CutPasteDetector.class,
|
||||||
Scope.JAVA_FILE_SCOPE));
|
Scope.JAVA_FILE_SCOPE));
|
||||||
|
|
||||||
private Node mLastMethod;
|
private UFunction mLastMethod;
|
||||||
private Map<String, MethodInvocation> mIds;
|
private Map<String, UCallExpression> mIds;
|
||||||
private Map<String, String> mLhs;
|
private Map<String, String> mLhs;
|
||||||
private Map<String, String> mCallOperands;
|
private Map<String, String> mCallOperands;
|
||||||
|
|
||||||
@@ -87,22 +79,22 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getApplicableMethodNames() {
|
public List<String> getApplicableFunctionNames() {
|
||||||
return Collections.singletonList("findViewById"); //$NON-NLS-1$
|
return Collections.singletonList("findViewById"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation call) {
|
String lhs = getLhs(node);
|
||||||
String lhs = getLhs(call);
|
|
||||||
if (lhs == null) {
|
if (lhs == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node method = JavaContext.findSurroundingMethod(call);
|
UFunction method = UastUtils.getContainingFunction(node);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return;
|
return;
|
||||||
} else if (method != mLastMethod) {
|
} else if (method != mLastMethod) {
|
||||||
@@ -112,16 +104,20 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
|||||||
mLastMethod = method;
|
mLastMethod = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
String callOperand = call.astOperand() != null ? call.astOperand().toString() : "";
|
UElement parent = node.getParent();
|
||||||
|
String callOperand = "";
|
||||||
|
if (parent instanceof UQualifiedExpression) {
|
||||||
|
callOperand = ((UQualifiedExpression)parent).getReceiver().renderString();
|
||||||
|
}
|
||||||
|
|
||||||
Expression first = call.astArguments().first();
|
UExpression first = node.getValueArguments().get(0);
|
||||||
if (first instanceof Select) {
|
if (first instanceof UQualifiedExpression) {
|
||||||
Select select = (Select) first;
|
UQualifiedExpression select = (UQualifiedExpression) first;
|
||||||
String id = select.astIdentifier().astValue();
|
String id = select.getSelector().renderString();
|
||||||
Expression operand = select.astOperand();
|
UExpression operand = select.getReceiver();
|
||||||
if (operand instanceof Select) {
|
if (operand instanceof UQualifiedExpression) {
|
||||||
Select type = (Select) operand;
|
UQualifiedExpression type = (UQualifiedExpression) operand;
|
||||||
if (type.astIdentifier().astValue().equals(RESOURCE_CLZ_ID)) {
|
if (type.getSelector().renderString().equals(RESOURCE_CLZ_ID)) {
|
||||||
if (mIds.containsKey(id)) {
|
if (mIds.containsKey(id)) {
|
||||||
if (lhs.equals(mLhs.get(id))) {
|
if (lhs.equals(mLhs.get(id))) {
|
||||||
return;
|
return;
|
||||||
@@ -129,45 +125,49 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
|||||||
if (!callOperand.equals(mCallOperands.get(id))) {
|
if (!callOperand.equals(mCallOperands.get(id))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodInvocation earlierCall = mIds.get(id);
|
UCallExpression earlierCall = mIds.get(id);
|
||||||
if (!isReachableFrom(method, earlierCall, call)) {
|
if (!isReachableFrom(method, earlierCall, node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Location location = context.getLocation(call);
|
Location location = UastAndroidUtils.getLocation(node);
|
||||||
Location secondary = context.getLocation(earlierCall);
|
Location secondary = UastAndroidUtils.getLocation(earlierCall);
|
||||||
secondary.setMessage("First usage here");
|
if (location != null && secondary != null) {
|
||||||
location.setSecondary(secondary);
|
secondary.setMessage("First usage here");
|
||||||
context.report(ISSUE, call, location, String.format(
|
location.setSecondary(secondary);
|
||||||
"The id `%1$s` has already been looked up in this method; possible " +
|
context.report(ISSUE, node, location, String.format(
|
||||||
"cut & paste error?", first.toString()));
|
"The id `%1$s` has already been looked up in this method; possible " +
|
||||||
|
"cut & paste error?", first.toString()));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mIds.put(id, call);
|
mIds.put(id, node);
|
||||||
mLhs.put(id, lhs);
|
mLhs.put(id, lhs);
|
||||||
mCallOperands.put(id, callOperand);
|
mCallOperands.put(id, callOperand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getLhs(@NonNull MethodInvocation call) {
|
private static String getLhs(@NonNull UCallExpression call) {
|
||||||
Node parent = call.getParent();
|
UElement parent = call.getParent();
|
||||||
if (parent instanceof Cast) {
|
if (UastBinaryExpressionWithTypeUtils.isTypeCast(parent)) {
|
||||||
|
assert parent != null;
|
||||||
parent = parent.getParent();
|
parent = parent.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent instanceof VariableDefinitionEntry) {
|
if (parent instanceof UVariable) {
|
||||||
VariableDefinitionEntry vde = (VariableDefinitionEntry) parent;
|
UVariable vde = (UVariable) parent;
|
||||||
return vde.astName().astValue();
|
return vde.getName();
|
||||||
} else if (parent instanceof BinaryExpression) {
|
} else if (parent instanceof UBinaryExpression) {
|
||||||
BinaryExpression be = (BinaryExpression) parent;
|
UBinaryExpression be = (UBinaryExpression) parent;
|
||||||
Expression left = be.astLeft();
|
UExpression left = be.getLeftOperand();
|
||||||
if (left instanceof VariableReference || left instanceof Select) {
|
if (left instanceof USimpleReferenceExpression || left instanceof UQualifiedExpression) {
|
||||||
return be.astLeft().toString();
|
return be.getLeftOperand().toString();
|
||||||
} else if (left instanceof ArrayAccess) {
|
} else if (left instanceof UArrayAccessExpression) {
|
||||||
ArrayAccess aa = (ArrayAccess) left;
|
UArrayAccessExpression aa = (UArrayAccessExpression) left;
|
||||||
return aa.astOperand().toString();
|
return aa.getReceiver().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,22 +175,21 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isReachableFrom(
|
private static boolean isReachableFrom(
|
||||||
@NonNull Node method,
|
@NonNull UElement method,
|
||||||
@NonNull MethodInvocation from,
|
@NonNull UCallExpression from,
|
||||||
@NonNull MethodInvocation to) {
|
@NonNull UCallExpression to) {
|
||||||
ReachableVisitor visitor = new ReachableVisitor(from, to);
|
ReachableVisitor visitor = new ReachableVisitor(from, to);
|
||||||
method.accept(visitor);
|
visitor.process(method);
|
||||||
|
|
||||||
return visitor.isReachable();
|
return visitor.isReachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ReachableVisitor extends ForwardingAstVisitor {
|
private static class ReachableVisitor extends UastVisitor {
|
||||||
@NonNull private final MethodInvocation mFrom;
|
@NonNull private final UCallExpression mFrom;
|
||||||
@NonNull private final MethodInvocation mTo;
|
@NonNull private final UCallExpression mTo;
|
||||||
private boolean mReachable;
|
private boolean mReachable;
|
||||||
private boolean mSeenEnd;
|
private boolean mSeenEnd;
|
||||||
|
|
||||||
public ReachableVisitor(@NonNull MethodInvocation from, @NonNull MethodInvocation to) {
|
public ReachableVisitor(@NonNull UCallExpression from, @NonNull UCallExpression to) {
|
||||||
mFrom = from;
|
mFrom = from;
|
||||||
mTo = to;
|
mTo = to;
|
||||||
}
|
}
|
||||||
@@ -200,43 +199,42 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitMethodInvocation(MethodInvocation node) {
|
public boolean visitCallExpression(@NotNull UCallExpression node) {
|
||||||
if (node == mFrom) {
|
if (node == mFrom) {
|
||||||
mReachable = true;
|
mReachable = true;
|
||||||
} else if (node == mTo) {
|
} else if (node == mTo) {
|
||||||
mSeenEnd = true;
|
mSeenEnd = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
return super.visitMethodInvocation(node);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitIf(If node) {
|
public boolean visitIfExpression(@NotNull UIfExpression node) {
|
||||||
Expression condition = node.astCondition();
|
UExpression condition = node.getCondition();
|
||||||
Statement body = node.astStatement();
|
UExpression body = node.getThenBranch();
|
||||||
Statement elseBody = node.astElseStatement();
|
UElement elseBody = node.getElseBranch();
|
||||||
if (condition != null) {
|
process(condition);
|
||||||
condition.accept(this);
|
|
||||||
}
|
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
boolean wasReachable = mReachable;
|
boolean wasReachable = mReachable;
|
||||||
body.accept(this);
|
process(body);
|
||||||
mReachable = wasReachable;
|
mReachable = wasReachable;
|
||||||
}
|
}
|
||||||
if (elseBody != null) {
|
if (elseBody != null) {
|
||||||
boolean wasReachable = mReachable;
|
boolean wasReachable = mReachable;
|
||||||
elseBody.accept(this);
|
process(elseBody);
|
||||||
mReachable = wasReachable;
|
mReachable = wasReachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
endVisit(node);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitNode(Node node) {
|
public void process(@NotNull UElement element) {
|
||||||
return mSeenEnd;
|
if (!mSeenEnd) {
|
||||||
|
super.process(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-28
@@ -14,33 +14,33 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Detector.JavaScanner;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
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.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.UFunction;
|
||||||
import lombok.ast.ConstructorInvocation;
|
import org.jetbrains.uast.UCallExpression;
|
||||||
|
import org.jetbrains.uast.UType;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for errors related to Date Formats
|
* Checks for errors related to Date Formats
|
||||||
*/
|
*/
|
||||||
public class DateFormatDetector extends Detector implements JavaScanner {
|
public class DateFormatDetector extends Detector implements UastScanner {
|
||||||
|
|
||||||
private static final Implementation IMPLEMENTATION = new Implementation(
|
private static final Implementation IMPLEMENTATION = new Implementation(
|
||||||
DateFormatDetector.class,
|
DateFormatDetector.class,
|
||||||
@@ -82,7 +82,7 @@ public class DateFormatDetector extends Detector implements JavaScanner {
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
@@ -91,22 +91,21 @@ public class DateFormatDetector extends Detector implements JavaScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitConstructor(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitConstructor(UastAndroidContext context, UCallExpression functionCall, UFunction constructor) {
|
||||||
@NonNull ConstructorInvocation node, @NonNull ResolvedMethod constructor) {
|
|
||||||
if (!specifiesLocale(constructor)) {
|
if (!specifiesLocale(constructor)) {
|
||||||
Location location = context.getLocation(node);
|
Location location = UastAndroidUtils.getLocation(functionCall);
|
||||||
String message =
|
String message =
|
||||||
"To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, " +
|
"To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, " +
|
||||||
"or `getTimeInstance()`, or use `new SimpleDateFormat(String template, " +
|
"or `getTimeInstance()`, or use `new SimpleDateFormat(String template, " +
|
||||||
"Locale locale)` with for example `Locale.US` for ASCII dates.";
|
"Locale locale)` with for example `Locale.US` for ASCII dates.";
|
||||||
context.report(DATE_FORMAT, node, location, message);
|
context.report(DATE_FORMAT, functionCall, location, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean specifiesLocale(@NonNull ResolvedMethod method) {
|
private static boolean specifiesLocale(@NonNull UFunction method) {
|
||||||
for (int i = 0, n = method.getArgumentCount(); i < n; i++) {
|
for (int i = 0, n = method.getValueParameterCount(); i < n; i++) {
|
||||||
TypeDescriptor argumentType = method.getArgumentType(i);
|
UType parameterType = method.getValueParameters().get(i).getType();
|
||||||
if (argumentType.matchesSignature(LOCALE_CLS)) {
|
if (parameterType.matchesFqName(LOCALE_CLS)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
|
import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
@@ -31,14 +31,14 @@ import static com.android.SdkConstants.EDIT_TEXT;
|
|||||||
import static com.android.SdkConstants.VALUE_TRUE;
|
import static com.android.SdkConstants.VALUE_TRUE;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|||||||
+9
-9
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_PKG_PREFIX;
|
import static com.android.SdkConstants.ANDROID_PKG_PREFIX;
|
||||||
import static com.android.SdkConstants.ANDROID_SUPPORT_PKG_PREFIX;
|
import static com.android.SdkConstants.ANDROID_SUPPORT_PKG_PREFIX;
|
||||||
@@ -39,14 +39,14 @@ import static com.android.resources.ResourceFolderType.MENU;
|
|||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|||||||
+10
-10
@@ -14,18 +14,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
import static com.android.SdkConstants.ATTR_ID;
|
import static com.android.SdkConstants.ATTR_ID;
|
||||||
@@ -27,17 +27,17 @@ import static com.android.ide.common.resources.configuration.FolderConfiguration
|
|||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
|||||||
+14
-14
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
|
|
||||||
import static com.android.SdkConstants.ATTR_NAME;
|
import static com.android.SdkConstants.ATTR_NAME;
|
||||||
@@ -27,19 +27,19 @@ import com.android.annotations.Nullable;
|
|||||||
import com.android.ide.common.resources.ResourceUrl;
|
import com.android.ide.common.resources.ResourceUrl;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.resources.ResourceType;
|
import com.android.resources.ResourceType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Location.Handle;
|
import com.android.tools.klint.detector.api.Location.Handle;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.TextFormat;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.utils.Pair;
|
import com.android.utils.Pair;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|||||||
+12
-12
@@ -14,21 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.DefaultPosition;
|
import com.android.tools.klint.detector.api.DefaultPosition;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Position;
|
import com.android.tools.klint.detector.api.Position;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|||||||
+12
-12
@@ -14,20 +14,20 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.ClassContext;
|
import com.android.tools.klint.detector.api.ClassContext;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|||||||
@@ -14,34 +14,28 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.CLASS_FRAGMENT;
|
import static com.android.SdkConstants.CLASS_FRAGMENT;
|
||||||
import static com.android.SdkConstants.CLASS_V4_FRAGMENT;
|
import static com.android.SdkConstants.CLASS_V4_FRAGMENT;
|
||||||
import static com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Detector.JavaScanner;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
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.lang.reflect.Modifier;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.ClassDeclaration;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.ConstructorDeclaration;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Node;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.NormalTypeBody;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.TypeMember;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that Fragment subclasses can be instantiated via
|
* Checks that Fragment subclasses can be instantiated via
|
||||||
@@ -52,7 +46,7 @@ import lombok.ast.TypeMember;
|
|||||||
* http://stackoverflow.com/questions/8058809/fragment-activity-crashes-on-screen-rotate
|
* http://stackoverflow.com/questions/8058809/fragment-activity-crashes-on-screen-rotate
|
||||||
* (and countless duplicates)
|
* (and countless duplicates)
|
||||||
*/
|
*/
|
||||||
public class FragmentDetector extends Detector implements JavaScanner {
|
public class FragmentDetector extends Detector implements UastScanner {
|
||||||
/** Are fragment subclasses instantiatable? */
|
/** Are fragment subclasses instantiatable? */
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"ValidFragment", //$NON-NLS-1$
|
"ValidFragment", //$NON-NLS-1$
|
||||||
@@ -86,80 +80,67 @@ public class FragmentDetector extends Detector implements JavaScanner {
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> applicableSuperClasses() {
|
public List<String> getApplicableSuperClasses() {
|
||||||
return Arrays.asList(CLASS_FRAGMENT, CLASS_V4_FRAGMENT);
|
return Arrays.asList(CLASS_FRAGMENT, CLASS_V4_FRAGMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkClass(@NonNull JavaContext context, @Nullable ClassDeclaration node,
|
public void visitClass(UastAndroidContext context, UClass cls) {
|
||||||
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
|
if (cls.hasModifier(UastModifier.ABSTRACT) || cls.isInterface()) {
|
||||||
if (node == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flags = node.astModifiers().getEffectiveModifierFlags();
|
if (!cls.getVisibility().isPublic()) {
|
||||||
if ((flags & Modifier.ABSTRACT) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flags & Modifier.PUBLIC) == 0) {
|
|
||||||
String message = String.format("This fragment class should be public (%1$s)",
|
String message = String.format("This fragment class should be public (%1$s)",
|
||||||
cls.getName());
|
cls.getFqName());
|
||||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
context.report(ISSUE, cls, UastAndroidUtils.getLocation(cls.getNameElement()), message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
|
if (UastUtils.getContainingClass(cls) != null && cls.hasModifier(UastModifier.INNER)) {
|
||||||
String message = String.format(
|
String message = String.format(
|
||||||
"This fragment inner class should be static (%1$s)", cls.getName());
|
"This fragment inner class should be static (%1$s)", cls.getName());
|
||||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
context.report(ISSUE, cls, UastAndroidUtils.getLocation(cls.getNameElement()), message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasDefaultConstructor = false;
|
boolean hasDefaultConstructor = false;
|
||||||
boolean hasConstructor = false;
|
boolean hasConstructor = false;
|
||||||
NormalTypeBody body = node.astBody();
|
|
||||||
if (body != null) {
|
for (UFunction constructor : cls.getConstructors()) {
|
||||||
for (TypeMember member : body.astMembers()) {
|
hasConstructor = true;
|
||||||
if (member instanceof ConstructorDeclaration) {
|
if (constructor.getValueParameterCount() == 0) {
|
||||||
hasConstructor = true;
|
if (constructor.getVisibility().isPublic()) {
|
||||||
ConstructorDeclaration constructor = (ConstructorDeclaration) member;
|
hasDefaultConstructor = true;
|
||||||
if (constructor.astParameters().isEmpty()) {
|
} else {
|
||||||
// The constructor must be public
|
Location location = UastAndroidUtils.getLocation(constructor.getNameElement());
|
||||||
if (constructor.astModifiers().isPublic()) {
|
context.report(ISSUE, constructor, location,
|
||||||
hasDefaultConstructor = true;
|
"The default constructor must be public");
|
||||||
} else {
|
// Also mark that we have a constructor so we don't complain again
|
||||||
Location location = context.getLocation(
|
// below since we've already emitted a more specific error related
|
||||||
constructor.astTypeName());
|
// to the default constructor
|
||||||
context.report(ISSUE, constructor, location,
|
hasDefaultConstructor = true;
|
||||||
"The default constructor must be public");
|
|
||||||
// Also mark that we have a constructor so we don't complain again
|
|
||||||
// below since we've already emitted a more specific error related
|
|
||||||
// to the default constructor
|
|
||||||
hasDefaultConstructor = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Location location = context.getLocation(constructor.astTypeName());
|
|
||||||
// TODO: Use separate issue for this which isn't an error
|
|
||||||
String message = "Avoid non-default constructors in fragments: "
|
|
||||||
+ "use a default constructor plus "
|
|
||||||
+ "`Fragment#setArguments(Bundle)` instead";
|
|
||||||
context.report(ISSUE, constructor, location, message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Location location = UastAndroidUtils.getLocation(constructor.getNameElement());
|
||||||
|
// TODO: Use separate issue for this which isn't an error
|
||||||
|
String message = "Avoid non-default constructors in fragments: "
|
||||||
|
+ "use a default constructor plus "
|
||||||
|
+ "`Fragment#setArguments(Bundle)` instead";
|
||||||
|
context.report(ISSUE, constructor, location, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasDefaultConstructor && hasConstructor) {
|
if (!hasDefaultConstructor && hasConstructor) {
|
||||||
String message = String.format(
|
String message = String.format(
|
||||||
"This fragment should provide a default constructor (a public " +
|
"This fragment should provide a default constructor (a public " +
|
||||||
"constructor with no arguments) (`%1$s`)",
|
"constructor with no arguments) (`%1$s`)",
|
||||||
cls.getName());
|
cls.getName());
|
||||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
context.report(ISSUE, cls, UastAndroidUtils.getLocation(cls.getNameElement()), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -14,25 +14,25 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Detector.JavaScanner;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
@@ -45,7 +45,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Check which makes sure that a full-backup-content descriptor file is valid and logical
|
* Check which makes sure that a full-backup-content descriptor file is valid and logical
|
||||||
*/
|
*/
|
||||||
public class FullBackupContentDetector extends ResourceXmlDetector implements JavaScanner {
|
public class FullBackupContentDetector extends ResourceXmlDetector implements UastScanner {
|
||||||
/**
|
/**
|
||||||
* Validation of {@code <full-backup-content>} XML elements
|
* Validation of {@code <full-backup-content>} XML elements
|
||||||
*/
|
*/
|
||||||
|
|||||||
+51
-71
@@ -14,36 +14,25 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.tools.klint.client.api.JavaParser;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedField;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
|
||||||
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.JavaContext;
|
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.BinaryExpression;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
import lombok.ast.BinaryOperator;
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
import lombok.ast.Expression;
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
import lombok.ast.IntegralLiteral;
|
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.StrictListAccessor;
|
|
||||||
import lombok.ast.StringLiteral;
|
|
||||||
|
|
||||||
public class GetSignaturesDetector extends Detector implements Detector.JavaScanner {
|
public class GetSignaturesDetector extends Detector implements UastScanner {
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
"PackageManagerGetSignatures", //$NON-NLS-1$
|
"PackageManagerGetSignatures", //$NON-NLS-1$
|
||||||
"Potential Multiple Certificate Exploit",
|
"Potential Multiple Certificate Exploit",
|
||||||
@@ -65,92 +54,83 @@ public class GetSignaturesDetector extends Detector implements Detector.JavaScan
|
|||||||
private static final String GET_PACKAGE_INFO = "getPackageInfo"; //$NON-NLS-1$
|
private static final String GET_PACKAGE_INFO = "getPackageInfo"; //$NON-NLS-1$
|
||||||
private static final int GET_SIGNATURES_FLAG = 0x00000040; //$NON-NLS-1$
|
private static final int GET_SIGNATURES_FLAG = 0x00000040; //$NON-NLS-1$
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
public List<String> getApplicableFunctionNames() {
|
||||||
public List<String> getApplicableMethodNames() {
|
|
||||||
return Collections.singletonList(GET_PACKAGE_INFO);
|
return Collections.singletonList(GET_PACKAGE_INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||||
@NonNull MethodInvocation node) {
|
UFunction resolved = node.resolve(context);
|
||||||
ResolvedNode resolved = context.resolve(node);
|
|
||||||
|
|
||||||
if (!(resolved instanceof ResolvedMethod) ||
|
if (resolved == null ||
|
||||||
!((ResolvedMethod) resolved).getContainingClass()
|
!UastUtils.getContainingClassOrEmpty(resolved).isSubclassOf(PACKAGE_MANAGER_CLASS)) {
|
||||||
.isSubclassOf(PACKAGE_MANAGER_CLASS, false)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StrictListAccessor<Expression, MethodInvocation> argumentList = node.astArguments();
|
|
||||||
|
List<UExpression> argumentList = node.getValueArguments();
|
||||||
|
|
||||||
// Ignore if the method doesn't fit our description.
|
// Ignore if the method doesn't fit our description.
|
||||||
if (argumentList != null && argumentList.size() == 2) {
|
if (argumentList.size() == 2) {
|
||||||
TypeDescriptor firstParameterType = context.getType(argumentList.first());
|
UType firstParameterType = argumentList.get(0).getExpressionType();
|
||||||
if (firstParameterType != null
|
if (firstParameterType != null
|
||||||
&& firstParameterType.matchesSignature(JavaParser.TYPE_STRING)) {
|
&& firstParameterType.matchesFqName(JavaParser.TYPE_STRING)) {
|
||||||
maybeReportIssue(calculateValue(context, argumentList.last()), context, node);
|
maybeReportIssue(calculateValue(context, argumentList.get(1)), context, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void maybeReportIssue(
|
private static void maybeReportIssue(
|
||||||
int flagValue, JavaContext context, MethodInvocation node) {
|
int flagValue, UastAndroidContext context, UCallExpression node) {
|
||||||
if ((flagValue & GET_SIGNATURES_FLAG) != 0) {
|
if ((flagValue & GET_SIGNATURES_FLAG) != 0) {
|
||||||
context.report(ISSUE, node, context.getLocation(node.astArguments().last()),
|
context.report(ISSUE, node, UastAndroidUtils.getLocation(node.getValueArguments().get(1)),
|
||||||
"Reading app signatures from getPackageInfo: The app signatures "
|
"Reading app signatures from getPackageInfo: The app signatures "
|
||||||
+ "could be exploited if not validated properly; "
|
+ "could be exploited if not validated properly; "
|
||||||
+ "see issue explanation for details.");
|
+ "see issue explanation for details.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int calculateValue(JavaContext context, Expression expression) {
|
private static int calculateValue(UastAndroidContext context, UExpression expression) {
|
||||||
// This function assumes that the only inputs to the expression are static integer
|
// This function assumes that the only inputs to the expression are static integer
|
||||||
// flags that combined via bitwise operands.
|
// flags that combined via bitwise operands.
|
||||||
if (expression instanceof IntegralLiteral) {
|
if (UastLiteralUtils.isIntegralLiteral(expression)) {
|
||||||
return ((IntegralLiteral) expression).astIntValue();
|
return (int) UastLiteralUtils.getLongValue((ULiteralExpression) expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedNode resolvedNode = context.resolve(expression);
|
if (expression instanceof UResolvable) {
|
||||||
if (resolvedNode instanceof ResolvedField) {
|
UDeclaration resolvedNode = ((UResolvable) expression).resolve(context);
|
||||||
Object value = ((ResolvedField) resolvedNode).getValue();
|
if (resolvedNode instanceof UVariable) {
|
||||||
if (value instanceof Integer) {
|
UExpression initializer = ((UVariable)resolvedNode).getInitializer();
|
||||||
return (Integer) value;
|
if (initializer != null) {
|
||||||
|
Object value = initializer.evaluate();
|
||||||
|
if (value instanceof Integer) {
|
||||||
|
return (Integer)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expression instanceof BinaryExpression) {
|
|
||||||
BinaryExpression binaryExpression = (BinaryExpression) expression;
|
|
||||||
BinaryOperator operator = binaryExpression.astOperator();
|
|
||||||
int leftValue = calculateValue(context, binaryExpression.astLeft());
|
|
||||||
int rightValue = calculateValue(context, binaryExpression.astRight());
|
|
||||||
|
|
||||||
if (operator == BinaryOperator.BITWISE_OR) {
|
|
||||||
|
if (expression instanceof UBinaryExpression) {
|
||||||
|
UBinaryExpression binaryExpression = (UBinaryExpression) expression;
|
||||||
|
UastBinaryOperator operator = binaryExpression.getOperator();
|
||||||
|
int leftValue = calculateValue(context, binaryExpression.getLeftOperand());
|
||||||
|
int rightValue = calculateValue(context, binaryExpression.getRightOperand());
|
||||||
|
|
||||||
|
if (operator == UastBinaryOperator.BITWISE_OR) {
|
||||||
return leftValue | rightValue;
|
return leftValue | rightValue;
|
||||||
}
|
}
|
||||||
if (operator == BinaryOperator.BITWISE_AND) {
|
if (operator == UastBinaryOperator.BITWISE_AND) {
|
||||||
return leftValue & rightValue;
|
return leftValue & rightValue;
|
||||||
}
|
}
|
||||||
if (operator == BinaryOperator.BITWISE_XOR) {
|
if (operator == UastBinaryOperator.BITWISE_XOR) {
|
||||||
return leftValue ^ rightValue;
|
return leftValue ^ rightValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isStringParameter(
|
|
||||||
@NonNull Expression expression, @NonNull JavaContext context) {
|
|
||||||
if (expression instanceof StringLiteral) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
ResolvedNode resolvedNode = context.resolve(expression);
|
|
||||||
if (resolvedNode instanceof ResolvedField) {
|
|
||||||
if (((ResolvedField) resolvedNode).getValue() instanceof String) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,13 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.FD_BUILD_TOOLS;
|
import static com.android.SdkConstants.FD_BUILD_TOOLS;
|
||||||
import static com.android.SdkConstants.GRADLE_PLUGIN_MINIMUM_VERSION;
|
import static com.android.SdkConstants.GRADLE_PLUGIN_MINIMUM_VERSION;
|
||||||
import static com.android.SdkConstants.GRADLE_PLUGIN_RECOMMENDED_VERSION;
|
import static com.android.SdkConstants.GRADLE_PLUGIN_RECOMMENDED_VERSION;
|
||||||
import static com.android.ide.common.repository.GradleCoordinate.COMPARE_PLUS_HIGHER;
|
import static com.android.ide.common.repository.GradleCoordinate.COMPARE_PLUS_HIGHER;
|
||||||
import static com.android.tools.lint.checks.ManifestDetector.TARGET_NEWER;
|
import static com.android.tools.klint.detector.api.LintUtils.findSubstring;
|
||||||
import static com.android.tools.lint.detector.api.LintUtils.findSubstring;
|
|
||||||
import static com.google.common.base.Charsets.UTF_8;
|
import static com.google.common.base.Charsets.UTF_8;
|
||||||
|
|
||||||
import com.android.SdkConstants;
|
import com.android.SdkConstants;
|
||||||
@@ -35,18 +34,18 @@ import com.android.ide.common.repository.GradleCoordinate;
|
|||||||
import com.android.ide.common.repository.GradleCoordinate.RevisionComponent;
|
import com.android.ide.common.repository.GradleCoordinate.RevisionComponent;
|
||||||
import com.android.ide.common.repository.SdkMavenRepository;
|
import com.android.ide.common.repository.SdkMavenRepository;
|
||||||
import com.android.sdklib.repository.PreciseRevision;
|
import com.android.sdklib.repository.PreciseRevision;
|
||||||
import com.android.tools.lint.client.api.LintClient;
|
import com.android.tools.klint.client.api.LintClient;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.TextFormat;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
@@ -336,7 +335,7 @@ public class GradleDetector extends Detector implements Detector.GradleScanner {
|
|||||||
"Not targeting the latest versions of Android; compatibility " +
|
"Not targeting the latest versions of Android; compatibility " +
|
||||||
"modes apply. Consider testing and updating this version. " +
|
"modes apply. Consider testing and updating this version. " +
|
||||||
"Consult the android.os.Build.VERSION_CODES javadoc for details.";
|
"Consult the android.os.Build.VERSION_CODES javadoc for details.";
|
||||||
report(context, valueCookie, TARGET_NEWER, message);
|
report(context, valueCookie, ManifestDetector.TARGET_NEWER, message);
|
||||||
}
|
}
|
||||||
if (version > 0) {
|
if (version > 0) {
|
||||||
mTargetSdkVersion = version;
|
mTargetSdkVersion = version;
|
||||||
|
|||||||
+11
-11
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_NS_NAME;
|
import static com.android.SdkConstants.ANDROID_NS_NAME;
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
@@ -34,16 +34,16 @@ import static com.android.SdkConstants.XMLNS_PREFIX;
|
|||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.TextFormat;
|
import com.android.tools.klint.detector.api.TextFormat;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
|||||||
@@ -14,35 +14,31 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
|
||||||
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.lang.reflect.Modifier;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.ast.ClassDeclaration;
|
import org.jetbrains.uast.*;
|
||||||
import lombok.ast.Node;
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that Handler implementations are top level classes or static.
|
* Checks that Handler implementations are top level classes or static.
|
||||||
* See the corresponding check in the android.os.Handler source code.
|
* See the corresponding check in the android.os.Handler source code.
|
||||||
*/
|
*/
|
||||||
public class HandlerDetector extends Detector implements Detector.JavaScanner {
|
public class HandlerDetector extends Detector implements UastScanner {
|
||||||
|
|
||||||
/** Potentially leaking handlers */
|
/** Potentially leaking handlers */
|
||||||
public static final Issue ISSUE = Issue.create(
|
public static final Issue ISSUE = Issue.create(
|
||||||
@@ -78,58 +74,39 @@ public class HandlerDetector extends Detector implements Detector.JavaScanner {
|
|||||||
return Speed.FAST;
|
return Speed.FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> applicableSuperClasses() {
|
public List<String> getApplicableSuperClasses() {
|
||||||
return Collections.singletonList(HANDLER_CLS);
|
return Collections.singletonList(HANDLER_CLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkClass(@NonNull JavaContext context, @Nullable ClassDeclaration declaration,
|
public void visitClass(UastAndroidContext context, UClass node) {
|
||||||
@NonNull Node node, @NonNull ResolvedClass cls) {
|
boolean x = node.hasModifier(UastModifier.INNER);
|
||||||
if (!isInnerClass(declaration)) {
|
if (!node.hasModifier(UastModifier.INNER)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isStaticClass(declaration)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only flag handlers using the default looper
|
// Only flag handlers using the default looper
|
||||||
if (hasLooperConstructorParameter(cls)) {
|
if (hasLooperConstructorParameter(node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node locationNode = node instanceof ClassDeclaration
|
UElement locationNode = node.getNameElement();
|
||||||
? ((ClassDeclaration) node).astName() : node;
|
Location location = UastAndroidUtils.getLocation(locationNode);
|
||||||
Location location = context.getLocation(locationNode);
|
context.report(ISSUE, node, location, String.format(
|
||||||
context.report(ISSUE, location, String.format(
|
"This Handler class should be static or leaks might occur (%1$s)",
|
||||||
"This Handler class should be static or leaks might occur (%1$s)",
|
node.getName()));
|
||||||
cls.getName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInnerClass(@Nullable ClassDeclaration node) {
|
private static boolean hasLooperConstructorParameter(@NonNull UClass cls) {
|
||||||
return node == null || // null class declarations means anonymous inner class
|
for (UFunction constructor : cls.getConstructors()) {
|
||||||
JavaContext.getParentOfType(node, ClassDeclaration.class, true) != null;
|
for (int i = 0, n = constructor.getValueParameterCount(); i < n; i++) {
|
||||||
}
|
UType type = constructor.getValueParameters().get(i).getType();
|
||||||
|
if (type.matchesFqName(LOOPER_CLS)) {
|
||||||
private static boolean isStaticClass(@Nullable ClassDeclaration node) {
|
|
||||||
if (node == null) {
|
|
||||||
// A null class declaration means anonymous inner class, and these can't be static
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int flags = node.astModifiers().getEffectiveModifierFlags();
|
|
||||||
return (flags & Modifier.STATIC) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasLooperConstructorParameter(@NonNull ResolvedClass cls) {
|
|
||||||
for (ResolvedMethod constructor : cls.getConstructors()) {
|
|
||||||
for (int i = 0, n = constructor.getArgumentCount(); i < n; i++) {
|
|
||||||
TypeDescriptor type = constructor.getArgumentType(i);
|
|
||||||
if (type.matchesSignature(LOOPER_CLS)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -14,22 +14,22 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
|
import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
import static com.android.SdkConstants.ATTR_DEBUGGABLE;
|
import static com.android.SdkConstants.ATTR_DEBUGGABLE;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Detector;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
import static com.android.SdkConstants.ATTR_CONTENT_DESCRIPTION;
|
import static com.android.SdkConstants.ATTR_CONTENT_DESCRIPTION;
|
||||||
@@ -26,14 +26,14 @@ import static com.android.SdkConstants.ATTR_TITLE;
|
|||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
|
import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
@@ -43,7 +43,7 @@ import static com.android.SdkConstants.TAG_ITEM;
|
|||||||
import static com.android.SdkConstants.TAG_PROVIDER;
|
import static com.android.SdkConstants.TAG_PROVIDER;
|
||||||
import static com.android.SdkConstants.TAG_RECEIVER;
|
import static com.android.SdkConstants.TAG_RECEIVER;
|
||||||
import static com.android.SdkConstants.TAG_SERVICE;
|
import static com.android.SdkConstants.TAG_SERVICE;
|
||||||
import static com.android.tools.lint.detector.api.LintUtils.endsWith;
|
import static com.android.tools.klint.detector.api.LintUtils.endsWith;
|
||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
@@ -51,26 +51,29 @@ import com.android.builder.model.ProductFlavor;
|
|||||||
import com.android.builder.model.ProductFlavorContainer;
|
import com.android.builder.model.ProductFlavorContainer;
|
||||||
import com.android.resources.Density;
|
import com.android.resources.Density;
|
||||||
import com.android.resources.ResourceFolderType;
|
import com.android.resources.ResourceFolderType;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Context;
|
import com.android.tools.klint.detector.api.Context;
|
||||||
import com.android.tools.lint.detector.api.Detector;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.LintUtils;
|
||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.klint.detector.api.Location;
|
||||||
import com.android.tools.lint.detector.api.LintUtils;
|
import com.android.tools.klint.detector.api.Project;
|
||||||
import com.android.tools.lint.detector.api.Location;
|
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||||
import com.android.tools.lint.detector.api.Project;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Speed;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
import com.android.tools.lint.detector.api.Speed;
|
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.uast.*;
|
||||||
|
import org.jetbrains.uast.check.UastAndroidContext;
|
||||||
|
import org.jetbrains.uast.check.UastScanner;
|
||||||
|
import org.jetbrains.uast.visitor.UastVisitor;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
@@ -99,24 +102,11 @@ import javax.imageio.ImageIO;
|
|||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
|
||||||
import lombok.ast.AstVisitor;
|
|
||||||
import lombok.ast.ConstructorInvocation;
|
|
||||||
import lombok.ast.Expression;
|
|
||||||
import lombok.ast.ForwardingAstVisitor;
|
|
||||||
import lombok.ast.MethodDeclaration;
|
|
||||||
import lombok.ast.MethodInvocation;
|
|
||||||
import lombok.ast.Node;
|
|
||||||
import lombok.ast.Select;
|
|
||||||
import lombok.ast.StrictListAccessor;
|
|
||||||
import lombok.ast.TypeReference;
|
|
||||||
import lombok.ast.TypeReferencePart;
|
|
||||||
import lombok.ast.VariableReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for common icon problems, such as wrong icon sizes, placing icons in the
|
* Checks for common icon problems, such as wrong icon sizes, placing icons in the
|
||||||
* density independent drawable folder, etc.
|
* density independent drawable folder, etc.
|
||||||
*/
|
*/
|
||||||
public class IconDetector extends ResourceXmlDetector implements Detector.JavaScanner {
|
public class IconDetector extends ResourceXmlDetector implements UastScanner {
|
||||||
|
|
||||||
private static final boolean INCLUDE_LDPI;
|
private static final boolean INCLUDE_LDPI;
|
||||||
static {
|
static {
|
||||||
@@ -158,7 +148,7 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
|||||||
* the manifest, menu files etc to see how icons are used
|
* the manifest, menu files etc to see how icons are used
|
||||||
*/
|
*/
|
||||||
private static final EnumSet<Scope> ICON_TYPE_SCOPE = EnumSet.of(Scope.ALL_RESOURCE_FILES,
|
private static final EnumSet<Scope> ICON_TYPE_SCOPE = EnumSet.of(Scope.ALL_RESOURCE_FILES,
|
||||||
Scope.JAVA_FILE, Scope.MANIFEST);
|
Scope.SOURCE_FILE, Scope.MANIFEST);
|
||||||
|
|
||||||
private static final Implementation IMPLEMENTATION_JAVA = new Implementation(
|
private static final Implementation IMPLEMENTATION_JAVA = new Implementation(
|
||||||
IconDetector.class,
|
IconDetector.class,
|
||||||
@@ -1965,53 +1955,67 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Implements JavaScanner ----
|
// ---- Implements UastScanner ----
|
||||||
|
|
||||||
private static final String NOTIFICATION_CLASS = "Notification"; //$NON-NLS-1$
|
private static final String NOTIFICATION_CLASS = "Notification"; //$NON-NLS-1$
|
||||||
private static final String NOTIFICATION_COMPAT_CLASS = "NotificationCompat"; //$NON-NLS-1$
|
|
||||||
|
private static final String NOTIFICATION_CLASS_FQNAME =
|
||||||
|
"android.app.Notification"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private static final String NOTIFICATION_COMPAT_CLASS_FQNAME =
|
||||||
|
"android.support.v4.app.NotificationCompat"; //$NON-NLS-1$
|
||||||
|
|
||||||
private static final String BUILDER_CLASS = "Builder"; //$NON-NLS-1$
|
private static final String BUILDER_CLASS = "Builder"; //$NON-NLS-1$
|
||||||
private static final String SET_SMALL_ICON = "setSmallIcon"; //$NON-NLS-1$
|
private static final String SET_SMALL_ICON = "setSmallIcon"; //$NON-NLS-1$
|
||||||
private static final String ON_CREATE_OPTIONS_MENU = "onCreateOptionsMenu"; //$NON-NLS-1$
|
private static final String ON_CREATE_OPTIONS_MENU = "onCreateOptionsMenu"; //$NON-NLS-1$
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
public UastVisitor createUastVisitor(UastAndroidContext context) {
|
||||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
return new NotificationFinder(context);
|
||||||
return new NotificationFinder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private final class NotificationFinder extends UastVisitor {
|
||||||
@Nullable
|
private UastAndroidContext mContext;
|
||||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
|
||||||
List<Class<? extends Node>> types = new ArrayList<Class<? extends Node>>(3);
|
|
||||||
types.add(MethodDeclaration.class);
|
|
||||||
types.add(ConstructorInvocation.class);
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class NotificationFinder extends ForwardingAstVisitor {
|
public NotificationFinder(UastAndroidContext mContext) {
|
||||||
@Override
|
this.mContext = mContext;
|
||||||
public boolean visitMethodDeclaration(MethodDeclaration node) {
|
|
||||||
if (ON_CREATE_OPTIONS_MENU.equals(node.astMethodName().astValue())) {
|
|
||||||
// Gather any R.menu references found in this method
|
|
||||||
node.accept(new MenuFinder());
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.visitMethodDeclaration(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visitConstructorInvocation(ConstructorInvocation node) {
|
public boolean visitFunction(@NotNull UFunction node) {
|
||||||
TypeReference reference = node.astTypeReference();
|
if (node.matchesName(ON_CREATE_OPTIONS_MENU)) {
|
||||||
StrictListAccessor<TypeReferencePart, TypeReference> parts = reference.astParts();
|
// Gather any R.menu references found in this method
|
||||||
String typeName = parts.last().astIdentifier().astValue();
|
new MenuFinder().process(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitFunction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visitCallExpression(@NotNull UCallExpression node) {
|
||||||
|
if (node.getKind() == UastCallKind.CONSTRUCTOR_CALL) {
|
||||||
|
visitConstructorInvocation(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitCallExpression(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visitConstructorInvocation(UCallExpression node) {
|
||||||
|
USimpleReferenceExpression reference = node.getClassReference();
|
||||||
|
if (reference == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String typeName = reference.getIdentifier();
|
||||||
if (NOTIFICATION_CLASS.equals(typeName)) {
|
if (NOTIFICATION_CLASS.equals(typeName)) {
|
||||||
StrictListAccessor<Expression, ConstructorInvocation> args = node.astArguments();
|
List<UExpression> args = node.getValueArguments();
|
||||||
if (args.size() == 3) {
|
if (args.size() == 3) {
|
||||||
if (args.first() instanceof Select && handleSelect((Select) args.first())) {
|
if (args.get(0) instanceof UQualifiedExpression
|
||||||
return super.visitConstructorInvocation(node);
|
&& handleSelect((UQualifiedExpression) args.get(0))) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node method = StringFormatDetector.getParentMethod(node);
|
UFunction method = UastUtils.getContainingFunction(node);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
// Must track local types
|
// Must track local types
|
||||||
String name = StringFormatDetector.getResourceForFirstArg(method, node);
|
String name = StringFormatDetector.getResourceForFirstArg(method, node);
|
||||||
@@ -2024,31 +2028,24 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (BUILDER_CLASS.equals(typeName)) {
|
} else if (BUILDER_CLASS.equals(typeName)) {
|
||||||
boolean isBuilder = false;
|
UClass resolvedClass = reference.resolveClass(mContext);
|
||||||
if (parts.size() == 1) {
|
boolean isBuilder = resolvedClass != null
|
||||||
isBuilder = true;
|
&& (resolvedClass.matchesFqName(NOTIFICATION_CLASS_FQNAME)
|
||||||
} else if (parts.size() == 2) {
|
|| resolvedClass.matchesFqName(NOTIFICATION_COMPAT_CLASS_FQNAME));
|
||||||
String clz = parts.first().astIdentifier().astValue();
|
|
||||||
if (NOTIFICATION_CLASS.equals(clz) || NOTIFICATION_COMPAT_CLASS.equals(clz)) {
|
|
||||||
isBuilder = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isBuilder) {
|
if (isBuilder) {
|
||||||
Node method = StringFormatDetector.getParentMethod(node);
|
UFunction method = UastUtils.getContainingFunction(node);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
SetIconFinder finder = new SetIconFinder();
|
SetIconFinder finder = new SetIconFinder();
|
||||||
method.accept(finder);
|
finder.process(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.visitConstructorInvocation(node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleSelect(Select select) {
|
private boolean handleSelect(UQualifiedExpression select) {
|
||||||
if (select.toString().startsWith(R_DRAWABLE_PREFIX)) {
|
if (select.renderString().startsWith(R_DRAWABLE_PREFIX)) {
|
||||||
String name = select.astIdentifier().astValue();
|
String name = select.getSelector().renderString();
|
||||||
if (mNotificationIcons == null) {
|
if (mNotificationIcons == null) {
|
||||||
mNotificationIcons = Sets.newHashSet();
|
mNotificationIcons = Sets.newHashSet();
|
||||||
}
|
}
|
||||||
@@ -2060,32 +2057,31 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class SetIconFinder extends ForwardingAstVisitor {
|
private final class SetIconFinder extends UastVisitor {
|
||||||
@Override
|
@Override
|
||||||
public boolean visitMethodInvocation(MethodInvocation node) {
|
public boolean visitCallExpression(@NotNull UCallExpression node) {
|
||||||
if (SET_SMALL_ICON.equals(node.astName().astValue())) {
|
if (SET_SMALL_ICON.equals(node.getFunctionName())) {
|
||||||
StrictListAccessor<Expression,MethodInvocation> arguments = node.astArguments();
|
List<UExpression> args = node.getValueArguments();
|
||||||
if (arguments.size() == 1 && arguments.first() instanceof Select) {
|
if (args.size() == 1 && args.get(0) instanceof UQualifiedExpression) {
|
||||||
handleSelect((Select) arguments.first());
|
handleSelect((UQualifiedExpression) args.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.visitMethodInvocation(node);
|
|
||||||
|
return super.visitCallExpression(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class MenuFinder extends ForwardingAstVisitor {
|
private final class MenuFinder extends UastVisitor {
|
||||||
@Override
|
@Override
|
||||||
public boolean visitSelect(Select node) {
|
public boolean visitQualifiedExpression(@NotNull UQualifiedExpression node) {
|
||||||
// R.type.name
|
// R.type.name
|
||||||
if (node.astOperand() instanceof Select) {
|
if (node.getReceiver() instanceof UQualifiedExpression) {
|
||||||
Select select = (Select) node.astOperand();
|
UQualifiedExpression select = (UQualifiedExpression) node.getReceiver();
|
||||||
if (select.astOperand() instanceof VariableReference) {
|
if (select.getReceiver() instanceof USimpleReferenceExpression) {
|
||||||
VariableReference reference = (VariableReference) select.astOperand();
|
USimpleReferenceExpression reference = (USimpleReferenceExpression) select.getReceiver();
|
||||||
if (reference.astIdentifier().astValue().equals(R_CLASS)) {
|
if (R_CLASS.equals(reference.getIdentifier())) {
|
||||||
String type = select.astIdentifier().astValue();
|
if (select.selectorMatches(MENU_TYPE)) {
|
||||||
|
String name = node.getSelector().renderString();
|
||||||
if (type.equals(MENU_TYPE)) {
|
|
||||||
String name = node.astIdentifier().astValue();
|
|
||||||
// Reclassify icons in the given menu as action bar icons
|
// Reclassify icons in the given menu as action bar icons
|
||||||
if (mMenuToIcons != null) {
|
if (mMenuToIcons != null) {
|
||||||
Collection<String> icons = mMenuToIcons.get(name);
|
Collection<String> icons = mMenuToIcons.get(name);
|
||||||
@@ -2101,7 +2097,7 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.visitSelect(node);
|
return super.visitQualifiedExpression(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.android.tools.lint.checks;
|
package com.android.tools.klint.checks;
|
||||||
|
|
||||||
import static com.android.SdkConstants.ANDROID_URI;
|
import static com.android.SdkConstants.ANDROID_URI;
|
||||||
import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
|
import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
|
||||||
@@ -23,13 +23,13 @@ import static com.android.SdkConstants.VIEW_INCLUDE;
|
|||||||
|
|
||||||
import com.android.annotations.NonNull;
|
import com.android.annotations.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
import com.android.tools.lint.detector.api.Category;
|
import com.android.tools.klint.detector.api.Category;
|
||||||
import com.android.tools.lint.detector.api.Implementation;
|
import com.android.tools.klint.detector.api.Implementation;
|
||||||
import com.android.tools.lint.detector.api.Issue;
|
import com.android.tools.klint.detector.api.Issue;
|
||||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.klint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.klint.detector.api.Severity;
|
||||||
import com.android.tools.lint.detector.api.XmlContext;
|
import com.android.tools.klint.detector.api.XmlContext;
|
||||||
|
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user