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="module-output" name="android-extensions-compiler" />
|
||||
</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 id="directory" name="kotlinc">
|
||||
<element id="dir-copy" path="$PROJECT_DIR$/dist/kotlinc" />
|
||||
|
||||
Generated
+8
@@ -3,6 +3,7 @@
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<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-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" />
|
||||
@@ -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$/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$/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$/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" />
|
||||
@@ -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$/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$/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$/core/util.runtime/util.runtime.iml" filepath="$PROJECT_DIR$/core/util.runtime/util.runtime.iml" group="core" />
|
||||
</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-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-7729](https://youtrack.jetbrains.com/issue/KT-7729) Add Android Lint checks for Kotlin (Android Studio 1.5)
|
||||
|
||||
### 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.modification.label=Field &modification
|
||||
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">
|
||||
<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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.client.api;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.detector.api.ClassContext;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Detector.ClassScanner;
|
||||
import com.android.tools.klint.detector.api.ClassContext;
|
||||
import com.android.tools.klint.detector.api.Detector;
|
||||
import com.android.tools.klint.detector.api.Detector.ClassScanner;
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
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;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Specialized visitor for running detectors on a class object model.
|
||||
@@ -90,9 +81,9 @@ class AsmVisitor {
|
||||
if (names != null) {
|
||||
checkFullClass = false;
|
||||
for (String element : names) {
|
||||
List<Detector.ClassScanner> list = mMethodNameToChecks.get(element);
|
||||
List<ClassScanner> list = mMethodNameToChecks.get(element);
|
||||
if (list == null) {
|
||||
list = new ArrayList<Detector.ClassScanner>();
|
||||
list = new ArrayList<ClassScanner>();
|
||||
mMethodNameToChecks.put(element, list);
|
||||
}
|
||||
list.add(scanner);
|
||||
@@ -103,9 +94,9 @@ class AsmVisitor {
|
||||
if (owners != null) {
|
||||
checkFullClass = false;
|
||||
for (String element : owners) {
|
||||
List<Detector.ClassScanner> list = mMethodOwnerToChecks.get(element);
|
||||
List<ClassScanner> list = mMethodOwnerToChecks.get(element);
|
||||
if (list == null) {
|
||||
list = new ArrayList<Detector.ClassScanner>();
|
||||
list = new ArrayList<ClassScanner>();
|
||||
mMethodOwnerToChecks.put(element, list);
|
||||
}
|
||||
list.add(scanner);
|
||||
|
||||
+3
-3
@@ -14,12 +14,12 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,11 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.client.api;
|
||||
|
||||
import static com.android.SdkConstants.DOT_CLASS;
|
||||
import static com.android.SdkConstants.DOT_JAR;
|
||||
import static org.objectweb.asm.Opcodes.ASM5;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
@@ -26,7 +22,6 @@ import com.android.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.Closeables;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
|
||||
@@ -40,6 +35,10 @@ import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
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. */
|
||||
@VisibleForTesting
|
||||
class ClassEntry implements Comparable<ClassEntry> {
|
||||
|
||||
+2
-2
@@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
|
||||
+13
-29
@@ -14,48 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.client.api;
|
||||
|
||||
import static com.android.SdkConstants.CURRENT_PLATFORM;
|
||||
import static com.android.SdkConstants.PLATFORM_WINDOWS;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.TextFormat;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.TextFormat;
|
||||
import com.android.utils.XmlUtils;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
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.w3c.dom.*;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
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.io.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
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
|
||||
* configuration data into {@code lint.xml} in the project directory.
|
||||
|
||||
@@ -14,53 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
@@ -72,6 +26,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.android.SdkConstants.*;
|
||||
|
||||
/**
|
||||
* Default simple implementation of an {@link SdkInfo}
|
||||
* <p>
|
||||
|
||||
@@ -14,28 +14,21 @@
|
||||
* 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.Nullable;
|
||||
import com.android.annotations.VisibleForTesting;
|
||||
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.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
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.google.common.annotations.Beta;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.utils.SdkUtils;
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.client.api;
|
||||
|
||||
import static com.android.SdkConstants.ATTR_VALUE;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
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.android.tools.klint.detector.api.JavaContext;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
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;
|
||||
import org.jetbrains.uast.UFile;
|
||||
|
||||
/**
|
||||
* 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_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.
|
||||
* @param context information about the file previously parsed
|
||||
* @param compilationUnit the compilation unit being disposed
|
||||
*/
|
||||
public void dispose(@NonNull JavaContext context, @NonNull Node 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();
|
||||
public void dispose(@NonNull JavaContext context, @NonNull UFile compilationUnit) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.SdkConstants;
|
||||
import com.android.annotations.NonNull;
|
||||
@@ -35,21 +26,21 @@ import com.android.prefs.AndroidLocation;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkVersionInfo;
|
||||
import com.android.sdklib.repository.local.LocalSdk;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.TextFormat;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Detector;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.TextFormat;
|
||||
import com.android.utils.XmlUtils;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import org.jetbrains.uast.UastConverter;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
@@ -59,13 +50,10 @@ import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static com.android.SdkConstants.*;
|
||||
import static com.android.tools.klint.detector.api.LintUtils.endsWith;
|
||||
|
||||
/**
|
||||
* Information about the tool embedding the lint analyzer. IDEs and other tools
|
||||
@@ -153,19 +141,6 @@ public abstract class LintClient {
|
||||
@Nullable
|
||||
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
|
||||
* original detector, but tools can replace detectors using this hook with a version
|
||||
@@ -406,6 +381,15 @@ public abstract class LintClient {
|
||||
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)
|
||||
* usually associated with a project.
|
||||
|
||||
@@ -14,24 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
@@ -40,79 +23,47 @@ import com.android.ide.common.res2.ResourceItem;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.repository.local.LocalSdk;
|
||||
import com.android.tools.lint.client.api.LintListener.EventType;
|
||||
import com.android.tools.lint.detector.api.ClassContext;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.JavaContext;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.lint.detector.api.ResourceContext;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.TextFormat;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.ClassContext;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Detector;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.JavaContext;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.ResourceContext;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.TextFormat;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.sun.istack.internal.NotNull;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastChecker;
|
||||
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.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
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.objectweb.asm.tree.*;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayDeque;
|
||||
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.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import lombok.ast.Annotation;
|
||||
import lombok.ast.AnnotationElement;
|
||||
import lombok.ast.AnnotationValue;
|
||||
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;
|
||||
import static com.android.SdkConstants.*;
|
||||
import static com.android.ide.common.resources.configuration.FolderConfiguration.QUALIFIER_SPLITTER;
|
||||
import static java.io.File.separator;
|
||||
|
||||
/**
|
||||
* Analyzes Android projects and files
|
||||
@@ -415,7 +366,7 @@ public class LintDriver {
|
||||
mScope = Scope.infer(projects);
|
||||
}
|
||||
|
||||
fireEvent(EventType.STARTING, null);
|
||||
fireEvent(LintListener.EventType.STARTING, null);
|
||||
|
||||
for (Project project : projects) {
|
||||
mPhase = 1;
|
||||
@@ -438,7 +389,7 @@ public class LintDriver {
|
||||
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) {
|
||||
@@ -484,7 +435,7 @@ public class LintDriver {
|
||||
|
||||
do {
|
||||
mPhase++;
|
||||
fireEvent(EventType.NEW_PHASE,
|
||||
fireEvent(LintListener.EventType.NEW_PHASE,
|
||||
new Context(this, project, null, project.getDir()));
|
||||
|
||||
// Narrow the scope down to the set of scopes requested by
|
||||
@@ -629,16 +580,16 @@ public class LintDriver {
|
||||
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) {
|
||||
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) {
|
||||
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();
|
||||
|
||||
Context projectContext = new Context(this, project, null, projectDir);
|
||||
fireEvent(EventType.SCANNING_PROJECT, projectContext);
|
||||
fireEvent(LintListener.EventType.SCANNING_PROJECT, projectContext);
|
||||
|
||||
List<Project> allLibraries = project.getAllLibraries();
|
||||
Set<Project> allProjects = new HashSet<Project>(allLibraries.size() + 1);
|
||||
@@ -885,7 +836,7 @@ public class LintDriver {
|
||||
List<Project> libraries = project.getAllLibraries();
|
||||
for (Project library : libraries) {
|
||||
Context libraryContext = new Context(this, library, project, projectDir);
|
||||
fireEvent(EventType.SCANNING_LIBRARY_PROJECT, libraryContext);
|
||||
fireEvent(LintListener.EventType.SCANNING_LIBRARY_PROJECT, libraryContext);
|
||||
mCurrentProject = library;
|
||||
|
||||
for (Detector check : mApplicableDetectors) {
|
||||
@@ -954,7 +905,7 @@ public class LintDriver {
|
||||
if (detectors != null) {
|
||||
ResourceVisitor v = new ResourceVisitor(parser, detectors,
|
||||
null);
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
v.visitFile(context, manifestFile);
|
||||
}
|
||||
}
|
||||
@@ -1014,9 +965,9 @@ public class LintDriver {
|
||||
}
|
||||
}
|
||||
|
||||
if (mScope.contains(Scope.JAVA_FILE) || mScope.contains(Scope.ALL_JAVA_FILES)) {
|
||||
List<Detector> checks = union(mScopeDetectors.get(Scope.JAVA_FILE),
|
||||
mScopeDetectors.get(Scope.ALL_JAVA_FILES));
|
||||
if (mScope.contains(Scope.SOURCE_FILE) || mScope.contains(Scope.ALL_SOURCE_FILES)) {
|
||||
List<Detector> checks = union(mScopeDetectors.get(Scope.SOURCE_FILE),
|
||||
mScopeDetectors.get(Scope.ALL_SOURCE_FILES));
|
||||
if (checks != null && !checks.isEmpty()) {
|
||||
List<File> files = project.getSubset();
|
||||
if (files != null) {
|
||||
@@ -1111,7 +1062,7 @@ public class LintDriver {
|
||||
List<File> files = project.getProguardFiles();
|
||||
for (File file : files) {
|
||||
Context context = new Context(this, project, main, file);
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
for (Detector detector : detectors) {
|
||||
if (detector.appliesTo(context, file)) {
|
||||
detector.beforeCheckFile(context);
|
||||
@@ -1137,7 +1088,7 @@ public class LintDriver {
|
||||
File file = new File(project.getDir(), relativePath);
|
||||
if (file.exists()) {
|
||||
Context context = new Context(this, project, main, file);
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
for (Detector detector : detectors) {
|
||||
if (detector.appliesTo(context, file)) {
|
||||
detector.beforeCheckFile(context);
|
||||
@@ -1476,12 +1427,6 @@ public class LintDriver {
|
||||
@Nullable Project main,
|
||||
@NonNull List<File> sourceFolders,
|
||||
@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();
|
||||
|
||||
// Gather all Java source files in a single pass; more efficient.
|
||||
@@ -1490,22 +1435,39 @@ public class LintDriver {
|
||||
gatherJavaFiles(folder, sources);
|
||||
}
|
||||
if (!sources.isEmpty()) {
|
||||
JavaVisitor visitor = new JavaVisitor(javaParser, checks);
|
||||
List<JavaContext> contexts = Lists.newArrayListWithExpectedSize(sources.size());
|
||||
for (File file : sources) {
|
||||
JavaContext context = new JavaContext(this, project, main, file, javaParser);
|
||||
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) {
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
visitor.visitFile(context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, 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) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
visitor.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,41 +1476,52 @@ public class LintDriver {
|
||||
@Nullable Project main,
|
||||
@NonNull List<Detector> checks,
|
||||
@NonNull List<File> files) {
|
||||
List<UastScanner> uastDetectors = new ArrayList<UastScanner>();
|
||||
|
||||
JavaParser javaParser = mClient.getJavaParser(project);
|
||||
if (javaParser == null) {
|
||||
mClient.log(null, "No java parser provided to lint: not running Java checks");
|
||||
for (Detector check : checks) {
|
||||
if (check instanceof UastScanner) {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (file.isFile() && file.getPath().endsWith(DOT_JAVA)) {
|
||||
contexts.add(new JavaContext(this, project, main, file, javaParser));
|
||||
if (!file.isFile()) {
|
||||
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) {
|
||||
@@ -1666,7 +1639,7 @@ public class LintDriver {
|
||||
if (dirChecks != null && !dirChecks.isEmpty()) {
|
||||
ResourceContext context = new ResourceContext(this, project, main, dir, type);
|
||||
String folderName = dir.getName();
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
for (Detector check : dirChecks) {
|
||||
if (check.appliesTo(type)) {
|
||||
check.beforeCheckFile(context);
|
||||
@@ -1693,11 +1666,11 @@ public class LintDriver {
|
||||
if (LintUtils.isXmlFile(file)) {
|
||||
XmlContext context = new XmlContext(this, project, main, file, type,
|
||||
visitor.getParser());
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
visitor.visitFile(context, file);
|
||||
} else if (binaryChecks != null && LintUtils.isBitmapFile(file)) {
|
||||
ResourceContext context = new ResourceContext(this, project, main, file, type);
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
visitor.visitBinaryResource(context);
|
||||
}
|
||||
if (mCanceled) {
|
||||
@@ -1739,7 +1712,7 @@ public class LintDriver {
|
||||
if (visitor != null) {
|
||||
XmlContext context = new XmlContext(this, project, main, file, type,
|
||||
visitor.getParser());
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
visitor.visitFile(context, file);
|
||||
}
|
||||
}
|
||||
@@ -1752,7 +1725,7 @@ public class LintDriver {
|
||||
if (visitor != null) {
|
||||
ResourceContext context = new ResourceContext(this, project, main, file,
|
||||
type);
|
||||
fireEvent(EventType.SCANNING_FILE, context);
|
||||
fireEvent(LintListener.EventType.SCANNING_FILE, context);
|
||||
visitor.visitBinaryResource(context);
|
||||
if (mCanceled) {
|
||||
return;
|
||||
@@ -1920,12 +1893,6 @@ public class LintDriver {
|
||||
return mDelegate.getProject(dir, referenceDir);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaParser getJavaParser(@Nullable Project project) {
|
||||
return mDelegate.getJavaParser(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File findResource(@NonNull String relativePath) {
|
||||
return mDelegate.findResource(relativePath);
|
||||
@@ -1939,7 +1906,7 @@ public class LintDriver {
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected ClassPathInfo getClassPath(@NonNull Project project) {
|
||||
protected LintClient.ClassPathInfo getClassPath(@NonNull Project project) {
|
||||
return mDelegate.getClassPath(project);
|
||||
}
|
||||
|
||||
@@ -2069,6 +2036,17 @@ public class LintDriver {
|
||||
public void closeConnection(@NonNull URLConnection connection) throws IOException {
|
||||
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;
|
||||
}
|
||||
} else if (classNode.outerClass != null && classNode.outerMethod == null
|
||||
&& isAnonymousClass(classNode)) {
|
||||
&& LintUtils.isAnonymousClass(classNode)) {
|
||||
if (isSuppressed(issue, classNode)) {
|
||||
return true;
|
||||
}
|
||||
@@ -2251,7 +2229,7 @@ public class LintDriver {
|
||||
}
|
||||
|
||||
if (classNode.outerClass != null && classNode.outerMethod == null
|
||||
&& isAnonymousClass(classNode)) {
|
||||
&& LintUtils.isAnonymousClass(classNode)) {
|
||||
ClassNode outer = getOuterClassNode(classNode);
|
||||
if (outer != null) {
|
||||
MethodNode m = findMethod(outer, CONSTRUCTOR_NAME, false);
|
||||
@@ -2347,44 +2325,31 @@ public class LintDriver {
|
||||
* issue in this class
|
||||
*/
|
||||
public boolean isSuppressed(@Nullable JavaContext context, @NonNull Issue issue,
|
||||
@Nullable Node scope) {
|
||||
@Nullable UElement scope) {
|
||||
boolean checkComments = mClient.checkForSuppressComments() &&
|
||||
context != null && context.containsCommentSuppress();
|
||||
context != null && context.containsCommentSuppress();
|
||||
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 == VariableDefinition.class) {
|
||||
// Variable
|
||||
VariableDefinition declaration = (VariableDefinition) scope;
|
||||
if (isSuppressed(issue, declaration.astModifiers())) {
|
||||
if (scope instanceof UVariable) {
|
||||
UVariable declaration = (UVariable) scope;
|
||||
if (isUastSuppressed(issue, declaration.getAnnotations())) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == MethodDeclaration.class) {
|
||||
// Method
|
||||
// Look for annotations on the method
|
||||
MethodDeclaration declaration = (MethodDeclaration) scope;
|
||||
if (isSuppressed(issue, declaration.astModifiers())) {
|
||||
} else if (scope instanceof UFunction) {
|
||||
UFunction declaration = (UFunction) scope;
|
||||
if (isUastSuppressed(issue, declaration.getAnnotations())) {
|
||||
return true;
|
||||
}
|
||||
} else if (type == ConstructorDeclaration.class) {
|
||||
// Constructor
|
||||
// Look for annotations on the method
|
||||
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())) {
|
||||
} else if (scope instanceof UClass) {
|
||||
UClass declaration = (UClass) scope;
|
||||
if (isUastSuppressed(issue, declaration.getAnnotations())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkComments && context.isSuppressedWithComment(scope, issue)) {
|
||||
return true;
|
||||
}
|
||||
//TODO check comments
|
||||
//if (checkComments && context.isSuppressedWithComment(scope, issue)) {
|
||||
// return true;
|
||||
//}
|
||||
|
||||
scope = scope.getParent();
|
||||
}
|
||||
@@ -2401,47 +2366,27 @@ public class LintDriver {
|
||||
* @return true if the issue or all issues should be suppressed for this
|
||||
* modifier
|
||||
*/
|
||||
private static boolean isSuppressed(@Nullable Issue issue, @Nullable Modifiers modifiers) {
|
||||
if (modifiers == null) {
|
||||
return false;
|
||||
}
|
||||
StrictListAccessor<Annotation, Modifiers> annotations = modifiers.astAnnotations();
|
||||
if (annotations == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Annotation annotation : annotations) {
|
||||
TypeReference t = annotation.astAnnotationTypeReference();
|
||||
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;
|
||||
private static boolean isUastSuppressed(@Nullable Issue issue, @Nullable List<UAnnotation> annotations) {
|
||||
for (UAnnotation annotation : annotations) {
|
||||
if (annotation.matchesName(SUPPRESS_LINT)
|
||||
|| annotation.matchesName("SuppressWarnings")) { //$NON-NLS-1$
|
||||
List<UNamedExpression> values = annotation.getValueArguments();
|
||||
for (UNamedExpression element : values) {
|
||||
UExpression valueNode = element.getExpression();
|
||||
String value = UastLiteralUtils.getValueIfStringLiteral(valueNode);
|
||||
if (value != null) {
|
||||
if (matches(issue, value)) {
|
||||
return true;
|
||||
}
|
||||
if (valueNode instanceof StringLiteral) {
|
||||
StringLiteral literal = (StringLiteral) valueNode;
|
||||
String value = literal.astValue();
|
||||
if (matches(issue, value)) {
|
||||
return true;
|
||||
}
|
||||
} else if (valueNode instanceof ArrayInitializer) {
|
||||
ArrayInitializer array = (ArrayInitializer) valueNode;
|
||||
StrictListAccessor<Expression, ArrayInitializer> expressions =
|
||||
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;
|
||||
}
|
||||
} else if (valueNode instanceof UCallExpression
|
||||
&& ((UCallExpression)valueNode).getKind() == JavaUastCallKinds.ARRAY_INITIALIZER) {
|
||||
UCallExpression array = (UCallExpression) valueNode;
|
||||
List<UExpression> expressions = array.getValueArguments();
|
||||
for (UExpression arrayElement : expressions) {
|
||||
String elementValue = UastLiteralUtils.getValueIfStringLiteral(arrayElement);
|
||||
if (elementValue != null) {
|
||||
if (matches(issue, elementValue)) {
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.client.api;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
+12
-20
@@ -13,30 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.client.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Detector;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.utils.SdkUtils;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static com.android.SdkConstants.*;
|
||||
import static com.android.tools.klint.detector.api.Detector.OtherFileScanner;
|
||||
|
||||
/**
|
||||
* 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()) {
|
||||
List<File> files = new ArrayList<File>(subset.size());
|
||||
for (File file : subset) {
|
||||
@@ -111,7 +103,7 @@ class OtherFileVisitor {
|
||||
}
|
||||
}
|
||||
if (!files.isEmpty()) {
|
||||
mFiles.put(Scope.JAVA_FILE, files);
|
||||
mFiles.put(Scope.SOURCE_FILE, files);
|
||||
}
|
||||
} else {
|
||||
List<File> files = Lists.newArrayListWithExpectedSize(100);
|
||||
@@ -119,7 +111,7 @@ class OtherFileVisitor {
|
||||
collectFiles(files, srcFolder);
|
||||
}
|
||||
if (!files.isEmpty()) {
|
||||
mFiles.put(Scope.JAVA_FILE, files);
|
||||
mFiles.put(Scope.SOURCE_FILE, files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,30 +14,20 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Detector.XmlScanner;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.ResourceContext;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Detector;
|
||||
import com.android.tools.klint.detector.api.Detector.XmlScanner;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.ResourceContext;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
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 org.w3c.dom.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.RandomAccess;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Specialized visitor for running detectors on resources: typically XML documents,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.Nullable;
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.Nullable;
|
||||
|
||||
@@ -14,34 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.client.api.LintDriver;
|
||||
import com.android.tools.lint.detector.api.Location.SearchDirection;
|
||||
import com.android.tools.lint.detector.api.Location.SearchHints;
|
||||
import com.android.tools.klint.client.api.LintDriver;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
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 org.objectweb.asm.tree.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.SdkConstants.*;
|
||||
|
||||
/**
|
||||
* A {@link Context} used when checking .class files.
|
||||
* <p/>
|
||||
@@ -261,7 +248,7 @@ public class ClassContext extends Context {
|
||||
*/
|
||||
@NonNull
|
||||
public Location getLocationForLine(int line, @Nullable String patternStart,
|
||||
@Nullable String patternEnd, @Nullable SearchHints hints) {
|
||||
@Nullable String patternEnd, @Nullable Location.SearchHints hints) {
|
||||
File sourceFile = getSourceFile();
|
||||
if (sourceFile != null) {
|
||||
// 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,
|
||||
SearchHints.create(BACKWARD).matchJavaSymbol());
|
||||
Location.SearchHints.create(Location.SearchDirection.BACKWARD).matchJavaSymbol());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -556,21 +543,21 @@ public class ClassContext extends Context {
|
||||
// to find a method, look up the corresponding line number then search
|
||||
// around it for a suitable tag, such as the class name.
|
||||
String pattern;
|
||||
SearchDirection searchMode;
|
||||
Location.SearchDirection searchMode;
|
||||
if (methodNode.name.equals(CONSTRUCTOR_NAME)) {
|
||||
searchMode = EOL_BACKWARD;
|
||||
searchMode = Location.SearchDirection.EOL_BACKWARD;
|
||||
if (isAnonymousClass(classNode.name)) {
|
||||
pattern = classNode.superName.substring(classNode.superName.lastIndexOf('/') + 1);
|
||||
} else {
|
||||
pattern = classNode.name.substring(classNode.name.lastIndexOf('$') + 1);
|
||||
}
|
||||
} else {
|
||||
searchMode = BACKWARD;
|
||||
searchMode = Location.SearchDirection.BACKWARD;
|
||||
pattern = methodNode.name;
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
if (instruction instanceof MethodInsnNode) {
|
||||
MethodInsnNode call = (MethodInsnNode) instruction;
|
||||
|
||||
@@ -14,19 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.client.api.Configuration;
|
||||
import com.android.tools.lint.client.api.LintClient;
|
||||
import com.android.tools.lint.client.api.LintDriver;
|
||||
import com.android.tools.lint.client.api.SdkInfo;
|
||||
import com.android.tools.klint.client.api.Configuration;
|
||||
import com.android.tools.klint.client.api.LintClient;
|
||||
import com.android.tools.klint.client.api.LintDriver;
|
||||
import com.android.tools.klint.client.api.SdkInfo;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import java.io.File;
|
||||
@@ -34,6 +29,8 @@ import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.android.SdkConstants.*;
|
||||
|
||||
/**
|
||||
* Context passed to the detectors during an analysis run. It provides
|
||||
* information about the file being analyzed, it allows shared properties (so
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.detector.api;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
|
||||
@@ -14,16 +14,18 @@
|
||||
* 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.Nullable;
|
||||
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 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.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
@@ -33,17 +35,7 @@ import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A detector is able to find a particular problem (or a set of related problems).
|
||||
@@ -70,192 +62,6 @@ import lombok.ast.Node;
|
||||
*/
|
||||
@Beta
|
||||
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 */
|
||||
public interface ClassScanner {
|
||||
/**
|
||||
@@ -664,52 +470,48 @@ public abstract class Detector {
|
||||
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")
|
||||
public boolean appliesToResourceRefs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("javadoc")
|
||||
public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull Node node, @NonNull String type, @NonNull String name,
|
||||
boolean isFramework) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> applicableSuperClasses() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkClass(@NonNull JavaContext context, @Nullable ClassDeclaration declaration,
|
||||
@NonNull Node node, @NonNull ResolvedClass resolvedClass) {
|
||||
}
|
||||
public void visitResourceReference(
|
||||
UastAndroidContext context,
|
||||
UElement element,
|
||||
String type,
|
||||
String name,
|
||||
boolean isFramework
|
||||
) {}
|
||||
|
||||
@Nullable @SuppressWarnings("javadoc")
|
||||
public List<String> getApplicableConstructorTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("javadoc")
|
||||
public void visitConstructor(
|
||||
@NonNull JavaContext context,
|
||||
@Nullable AstVisitor visitor,
|
||||
@NonNull ConstructorInvocation node,
|
||||
@NonNull ResolvedMethod constructor) {
|
||||
public List<String> getApplicableSuperClasses() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visitClass(UastAndroidContext context, UClass node) {
|
||||
|
||||
}
|
||||
|
||||
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: ----
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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.google.common.annotations.Beta;
|
||||
|
||||
@@ -14,12 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.detector.api;
|
||||
|
||||
import static com.android.tools.lint.detector.api.TextFormat.RAW;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.client.api.Configuration;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -142,7 +139,7 @@ public final class Issue implements Comparable<Issue> {
|
||||
*/
|
||||
@NonNull
|
||||
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
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
||||
import com.android.tools.lint.client.api.LintDriver;
|
||||
import com.android.tools.klint.client.api.LintDriver;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.ClassDeclaration;
|
||||
import lombok.ast.ConstructorDeclaration;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.MethodDeclaration;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.Position;
|
||||
import static com.android.SdkConstants.CLASS_CONTEXT;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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$
|
||||
|
||||
/** The parse tree */
|
||||
private Node mCompilationUnit;
|
||||
|
||||
/** The parser which produced the parse tree */
|
||||
private final JavaParser mParser;
|
||||
private UFile mCompilationUnit;
|
||||
|
||||
/**
|
||||
* 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 Project project,
|
||||
@Nullable Project main,
|
||||
@NonNull File file,
|
||||
@NonNull JavaParser parser) {
|
||||
@NonNull File 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
|
||||
* @return a location for the given node
|
||||
*/
|
||||
@NonNull
|
||||
public Location getLocation(@NonNull Node node) {
|
||||
return mParser.getLocation(this, node);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public JavaParser getParser() {
|
||||
return mParser;
|
||||
@Override
|
||||
public Location getLocation(@NotNull UElement element) {
|
||||
return UastAndroidContext.DefaultImpls.getLocation(this, element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Node getCompilationUnit() {
|
||||
public UFile getCompilationUnit() {
|
||||
return mCompilationUnit;
|
||||
}
|
||||
|
||||
@@ -103,7 +84,7 @@ public class JavaContext extends Context {
|
||||
*
|
||||
* @param compilationUnit the parse tree
|
||||
*/
|
||||
public void setCompilationUnit(@Nullable Node compilationUnit) {
|
||||
public void setCompilationUnit(@Nullable UFile 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 message the message for this warning
|
||||
*/
|
||||
@Override
|
||||
public void report(
|
||||
@NonNull Issue issue,
|
||||
@Nullable Node scope,
|
||||
@Nullable Location location,
|
||||
@NonNull String message) {
|
||||
@NonNull Issue issue,
|
||||
@Nullable UElement scope,
|
||||
@Nullable Location location,
|
||||
@NonNull String message) {
|
||||
if (scope != null && mDriver.isSuppressed(this, issue, scope)) {
|
||||
return;
|
||||
}
|
||||
super.report(issue, location, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error.
|
||||
* Like {@link #report(Issue, 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
|
||||
@Nullable
|
||||
protected String getSuppressCommentPrefix() {
|
||||
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
|
||||
* {@code android.content.Context}
|
||||
@@ -235,160 +133,35 @@ public class JavaContext extends Context {
|
||||
* @param node the method call node
|
||||
* @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
|
||||
// same semantics; only use this one if we can resolve types
|
||||
// and we're certain this is the Context method
|
||||
ResolvedNode resolved = resolve(node);
|
||||
if (resolved instanceof JavaParser.ResolvedMethod) {
|
||||
JavaParser.ResolvedMethod method = (JavaParser.ResolvedMethod) resolved;
|
||||
ResolvedClass containingClass = method.getContainingClass();
|
||||
if (containingClass.isSubclassOf(CLASS_CONTEXT, false)) {
|
||||
UFunction resolved = node.resolve(this);
|
||||
UClass containingClass = UastUtils.getContainingClass(resolved);
|
||||
if (resolved != null && containingClass != null) {
|
||||
if (containingClass.isSubclassOf(CLASS_CONTEXT)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first ancestor node of the given type
|
||||
*
|
||||
* @param element the element to search from
|
||||
* @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
|
||||
@Override
|
||||
public JavaContext getLintContext() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first ancestor node of the given type
|
||||
*
|
||||
* @param element the element to search from
|
||||
* @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;
|
||||
@NotNull
|
||||
@Override
|
||||
public List<UastConverter> getConverters() {
|
||||
return getClient().getConverters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first ancestor node of the given type, stopping at the given type
|
||||
*
|
||||
* @param element the element to search from
|
||||
* @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));
|
||||
@org.jetbrains.annotations.Nullable
|
||||
@Override
|
||||
public UElement convert(@Nullable Object element) {
|
||||
return UastContext.DefaultImpls.convert(this, element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,25 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import static com.android.SdkConstants.*;
|
||||
|
||||
/**
|
||||
* Abstract class specifically intended for layout detectors which provides some
|
||||
* common utility methods shared by layout detectors.
|
||||
|
||||
@@ -14,25 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
@@ -53,7 +35,7 @@ import com.android.sdklib.AndroidVersion;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkVersionInfo;
|
||||
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.SdkUtils;
|
||||
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.Lists;
|
||||
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.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
@@ -74,19 +57,14 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayDeque;
|
||||
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.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
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.
|
||||
@@ -796,7 +774,7 @@ public class LintUtils {
|
||||
* qualified name
|
||||
*/
|
||||
public static boolean isImported(
|
||||
@Nullable lombok.ast.Node compilationUnit,
|
||||
@Nullable UFile compilationUnit,
|
||||
@NonNull String fullyQualifiedName) {
|
||||
if (compilationUnit == null) {
|
||||
return false;
|
||||
@@ -805,26 +783,27 @@ public class LintUtils {
|
||||
int dotLength = fullyQualifiedName.length() - dotIndex;
|
||||
|
||||
boolean imported = false;
|
||||
for (lombok.ast.Node rootNode : compilationUnit.getChildren()) {
|
||||
if (rootNode instanceof ImportDeclaration) {
|
||||
ImportDeclaration importDeclaration = (ImportDeclaration) rootNode;
|
||||
String fqn = importDeclaration.asFullyQualifiedName();
|
||||
if (fqn.equals(fullyQualifiedName)) {
|
||||
return true;
|
||||
} else if (fullyQualifiedName.regionMatches(dotIndex, fqn,
|
||||
fqn.length() - dotLength, dotLength)) {
|
||||
// This import is importing the class name using some other prefix, so there
|
||||
// fully qualified class name cannot be imported under that name
|
||||
return false;
|
||||
} else if (importDeclaration.astStarImport()
|
||||
&& fqn.regionMatches(0, fqn, 0, dotIndex + 1)) {
|
||||
imported = true;
|
||||
// but don't break -- keep searching in case there's a non-wildcard
|
||||
// import of the specific class name, e.g. if we're looking for
|
||||
// android.content.SharedPreferences.Editor, don't match on the following:
|
||||
// import android.content.SharedPreferences.*;
|
||||
// import foo.bar.Editor;
|
||||
}
|
||||
for (UImportStatement importStatement : compilationUnit.getImportStatements()) {
|
||||
String fqn = importStatement.getNameToImport();
|
||||
if (fqn == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fqn.equals(fullyQualifiedName)) {
|
||||
return true;
|
||||
} else if (fullyQualifiedName.regionMatches(dotIndex, fqn,
|
||||
fqn.length() - dotLength, dotLength)) {
|
||||
// This import is importing the class name using some other prefix, so there
|
||||
// fully qualified class name cannot be imported under that name
|
||||
return false;
|
||||
} else if (importStatement.isStarImport()
|
||||
&& fqn.regionMatches(0, fqn, 0, dotIndex + 1)) {
|
||||
imported = true;
|
||||
// but don't break -- keep searching in case there's a non-wildcard
|
||||
// import of the specific class name, e.g. if we're looking for
|
||||
// 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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.detector.api;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.detector.api;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.annotations.NonNull;
|
||||
@@ -28,10 +28,10 @@ import com.android.resources.ResourceFolderType;
|
||||
import com.android.sdklib.AndroidVersion;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkVersionInfo;
|
||||
import com.android.tools.lint.client.api.CircularDependencyException;
|
||||
import com.android.tools.lint.client.api.Configuration;
|
||||
import com.android.tools.lint.client.api.LintClient;
|
||||
import com.android.tools.lint.client.api.SdkInfo;
|
||||
import com.android.tools.klint.client.api.CircularDependencyException;
|
||||
import com.android.tools.klint.client.api.Configuration;
|
||||
import com.android.tools.klint.client.api.LintClient;
|
||||
import com.android.tools.klint.client.api.SdkInfo;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* 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.Nullable;
|
||||
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 java.io.File;
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* 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.resources.ResourceFolderType;
|
||||
|
||||
@@ -14,27 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.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;
|
||||
package com.android.tools.klint.detector.api;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.google.common.annotations.Beta;
|
||||
import org.jetbrains.uast.UastConverterUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.SdkConstants.*;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -80,14 +72,14 @@ public enum Scope {
|
||||
* Issues which are only affected by a single Java source file can be
|
||||
* 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.
|
||||
* <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.
|
||||
@@ -143,10 +135,10 @@ public enum Scope {
|
||||
if (size == 2) {
|
||||
// When single checking a Java source file, we check both its Java source
|
||||
// and the associated class files
|
||||
return scopes.contains(JAVA_FILE) && scopes.contains(CLASS_FILE);
|
||||
return scopes.contains(SOURCE_FILE) && scopes.contains(CLASS_FILE);
|
||||
} else {
|
||||
return size == 1 &&
|
||||
(scopes.contains(JAVA_FILE)
|
||||
(scopes.contains(SOURCE_FILE)
|
||||
|| scopes.contains(CLASS_FILE)
|
||||
|| scopes.contains(RESOURCE_FILE)
|
||||
|| scopes.contains(PROGUARD_FILE)
|
||||
@@ -192,7 +184,7 @@ public enum Scope {
|
||||
} else if (name.endsWith(DOT_XML)) {
|
||||
scope.add(RESOURCE_FILE);
|
||||
} else if (name.endsWith(DOT_JAVA)) {
|
||||
scope.add(JAVA_FILE);
|
||||
scope.add(SOURCE_FILE);
|
||||
} else if (name.endsWith(DOT_CLASS)) {
|
||||
scope.add(CLASS_FILE);
|
||||
} else if (name.endsWith(DOT_GRADLE)) {
|
||||
@@ -210,6 +202,9 @@ public enum Scope {
|
||||
scope.add(RESOURCE_FILE);
|
||||
scope.add(BINARY_RESOURCE_FILE);
|
||||
scope.add(RESOURCE_FOLDER);
|
||||
} else if (UastConverterUtils.isFileSupported(
|
||||
project.getClient().getConverters(), name)) {
|
||||
scope.add(SOURCE_FILE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -231,7 +226,7 @@ public enum Scope {
|
||||
/** Scope-set used for detectors which scan all resources */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
@@ -248,8 +243,8 @@ public enum Scope {
|
||||
public static final EnumSet<Scope> MANIFEST_AND_RESOURCE_SCOPE =
|
||||
EnumSet.of(Scope.MANIFEST, Scope.RESOURCE_FILE);
|
||||
/** Scope-set used for detectors which are affected by single XML and Java source files */
|
||||
public static final EnumSet<Scope> JAVA_AND_RESOURCE_FILES =
|
||||
EnumSet.of(RESOURCE_FILE, JAVA_FILE);
|
||||
public static final EnumSet<Scope> SOURCE_AND_RESOURCE_FILES =
|
||||
EnumSet.of(RESOURCE_FILE, SOURCE_FILE);
|
||||
/** Scope-set used for analyzing individual class files and all resource files */
|
||||
public static final EnumSet<Scope> CLASS_AND_ALL_RESOURCE_FILES =
|
||||
EnumSet.of(ALL_RESOURCE_FILES, CLASS_FILE);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.Nullable;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.google.common.annotations.Beta;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.utils.SdkUtils;
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
* 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.Nullable;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.client.api.LintDriver;
|
||||
import com.android.tools.lint.client.api.XmlParser;
|
||||
import com.android.tools.klint.client.api.LintDriver;
|
||||
import com.android.tools.klint.client.api.XmlParser;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
import static com.android.SdkConstants.ANDROID_URI;
|
||||
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.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
+28
-34
@@ -14,35 +14,34 @@
|
||||
* 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.lint.client.api.JavaParser.ResolvedNode;
|
||||
import static com.android.tools.lint.client.api.JavaParser.TYPE_OBJECT;
|
||||
import static com.android.tools.lint.client.api.JavaParser.TYPE_STRING;
|
||||
import static com.android.tools.klint.client.api.JavaParser.TYPE_OBJECT;
|
||||
import static com.android.tools.klint.client.api.JavaParser.TYPE_STRING;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.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.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
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.
|
||||
*/
|
||||
public class AddJavascriptInterfaceDetector extends Detector implements Detector.JavaScanner {
|
||||
public class AddJavascriptInterfaceDetector extends Detector implements UastScanner {
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
"AddJavascriptInterface", //$NON-NLS-1$
|
||||
"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 ADD_JAVASCRIPT_INTERFACE = "addJavascriptInterface"; //$NON-NLS-1$
|
||||
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Speed getSpeed() {
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Collections.singletonList(ADD_JAVASCRIPT_INTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation node) {
|
||||
// Ignore the issue if we never build for any API less than 17.
|
||||
if (context.getMainProject().getMinSdk() >= 17) {
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
if (context.getLintContext().getMainProject().getMinSdk() >= 17) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore if the method doesn't fit our description.
|
||||
ResolvedNode resolved = context.resolve(node);
|
||||
if (!(resolved instanceof ResolvedMethod)) {
|
||||
UFunction resolvedFunction = node.resolveOrEmpty(context);
|
||||
UClass containingClass = UastUtils.getContainingClassOrEmpty(resolvedFunction);
|
||||
if (!containingClass.isSubclassOf(WEB_VIEW)) {
|
||||
return;
|
||||
}
|
||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
||||
if (!method.getContainingClass().isSubclassOf(WEB_VIEW, false)) {
|
||||
return;
|
||||
}
|
||||
if (method.getArgumentCount() != 2
|
||||
|| !method.getArgumentType(0).matchesName(TYPE_OBJECT)
|
||||
|| !method.getArgumentType(1).matchesName(TYPE_STRING)) {
|
||||
List<UVariable> valueParameters = resolvedFunction.getValueParameters();
|
||||
if (node.getValueArgumentCount() != 2
|
||||
|| !valueParameters.get(0).getType().matchesFqName(TYPE_OBJECT)
|
||||
|| !valueParameters.get(1).getType().matchesFqName(TYPE_STRING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String message = "`WebView.addJavascriptInterface` should not be called with minSdkVersion < 17 for security reasons: " +
|
||||
"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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.ConstantEvaluator;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.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.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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 java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
|
||||
/**
|
||||
* 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(
|
||||
AlarmDetector.class,
|
||||
@@ -82,51 +76,38 @@ public class AlarmDetector extends Detector implements Detector.JavaScanner {
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Collections.singletonList("setRepeating");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation node) {
|
||||
ResolvedNode resolved = context.resolve(node);
|
||||
if (resolved instanceof ResolvedMethod) {
|
||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
||||
if (method.getContainingClass().matches("android.app.AlarmManager")
|
||||
&& method.getArgumentCount() == 4) {
|
||||
ensureAtLeast(context, node, 1, 5000L);
|
||||
ensureAtLeast(context, node, 2, 60000L);
|
||||
}
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
UFunction setRepeatingFunction = node.resolve(context);
|
||||
UClass containingClass = UastUtils.getContainingClassOrEmpty(setRepeatingFunction);
|
||||
|
||||
if (containingClass.matchesFqName("android.app.AlarmManager")
|
||||
&& node.getValueArgumentCount() == 4) {
|
||||
ensureAtLeast(context, node, 1, 5000L);
|
||||
ensureAtLeast(context, node, 2, 60000L);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureAtLeast(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation node, int parameter, long min) {
|
||||
Iterator<Expression> iterator = node.astArguments().iterator();
|
||||
Expression argument = null;
|
||||
for (int i = 0; i <= parameter; i++) {
|
||||
if (!iterator.hasNext()) {
|
||||
return;
|
||||
}
|
||||
argument = iterator.next();
|
||||
}
|
||||
if (argument == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long value = getLongValue(context, argument);
|
||||
private static void ensureAtLeast(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression node, int parameter, long min) {
|
||||
UExpression arg = node.getValueArguments().get(parameter);
|
||||
long value = getLongValue(arg);
|
||||
if (value < min) {
|
||||
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);
|
||||
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) {
|
||||
Object value = ConstantEvaluator.evaluate(context, argument);
|
||||
private static long getLongValue(@NonNull UExpression argument) {
|
||||
Object value = argument.evaluate();
|
||||
if (value instanceof Number) {
|
||||
return ((Number)value).longValue();
|
||||
}
|
||||
|
||||
+40
-38
@@ -14,7 +14,7 @@
|
||||
* 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.VALUE_ALWAYS;
|
||||
@@ -22,19 +22,26 @@ import static com.android.SdkConstants.VALUE_IF_ROOM;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector.JavaScanner;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.JavaContext;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.JavaContext;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.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 java.util.ArrayList;
|
||||
@@ -42,17 +49,12 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
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
|
||||
* MenuItem.SHOW_AS_ACTION_ALWAYS in code), which is usually a style guide violation.
|
||||
* (Use ifRoom instead).
|
||||
*/
|
||||
public class AlwaysShowActionDetector extends ResourceXmlDetector implements JavaScanner {
|
||||
public class AlwaysShowActionDetector extends ResourceXmlDetector implements UastScanner {
|
||||
|
||||
/** The main issue discovered by this detector */
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -78,7 +80,7 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav
|
||||
Severity.WARNING,
|
||||
new Implementation(
|
||||
AlwaysShowActionDetector.class,
|
||||
Scope.JAVA_AND_RESOURCE_FILES,
|
||||
Scope.SOURCE_AND_RESOURCE_FILES,
|
||||
Scope.RESOURCE_FILE_SCOPE))
|
||||
.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);
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Override
|
||||
public
|
||||
List<Class<? extends Node>> getApplicableNodeTypes() {
|
||||
return Collections.<Class<? extends Node>>singletonList(Select.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
||||
public UastVisitor createUastVisitor(UastAndroidContext context) {
|
||||
return new FieldAccessChecker(context);
|
||||
}
|
||||
|
||||
private class FieldAccessChecker extends ForwardingAstVisitor {
|
||||
private final JavaContext mContext;
|
||||
private class FieldAccessChecker extends UastVisitor {
|
||||
private final UastAndroidContext mContext;
|
||||
|
||||
public FieldAccessChecker(JavaContext context) {
|
||||
public FieldAccessChecker(UastAndroidContext context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitSelect(Select node) {
|
||||
String description = node.astIdentifier().astValue();
|
||||
public boolean visitQualifiedExpression(@NotNull UQualifiedExpression node) {
|
||||
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 isAlways = description.equals("SHOW_AS_ACTION_ALWAYS"); //$NON-NLS-1$
|
||||
if ((isIfRoom || isAlways)
|
||||
&& node.astOperand().toString().equals("MenuItem")) { //$NON-NLS-1$
|
||||
&& node.getReceiver().renderString().equals("MenuItem")) { //$NON-NLS-1$
|
||||
if (isAlways) {
|
||||
if (mContext.getDriver().isSuppressed(mContext, ISSUE, node)) {
|
||||
return super.visitSelect(node);
|
||||
JavaContext lintContext = mContext.getLintContext();
|
||||
if (lintContext.getDriver().isSuppressed(lintContext, ISSUE, node)) {
|
||||
return false;
|
||||
}
|
||||
if (mAlwaysFields == null) {
|
||||
mAlwaysFields = new ArrayList<Location>();
|
||||
}
|
||||
mAlwaysFields.add(mContext.getLocation(node));
|
||||
mAlwaysFields.add(UastAndroidUtils.getLocation(node));
|
||||
} else {
|
||||
mHasIfRoomRefs = true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitSelect(node);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+55
-90
@@ -14,51 +14,36 @@
|
||||
* 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.SUPPRESS_LINT;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.client.api.IssueRegistry;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.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.android.tools.klint.client.api.IssueRegistry;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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 java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.Annotation;
|
||||
import lombok.ast.AnnotationElement;
|
||||
import lombok.ast.AnnotationValue;
|
||||
import lombok.ast.ArrayInitializer;
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.Block;
|
||||
import lombok.ast.ConstructorDeclaration;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.ForwardingAstVisitor;
|
||||
import lombok.ast.MethodDeclaration;
|
||||
import lombok.ast.Modifiers;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.Select;
|
||||
import lombok.ast.StrictListAccessor;
|
||||
import lombok.ast.StringLiteral;
|
||||
import lombok.ast.TypeBody;
|
||||
import lombok.ast.VariableDefinition;
|
||||
import lombok.ast.VariableDefinitionEntry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
import org.jetbrains.uast.java.JavaUastCallKinds;
|
||||
import org.jetbrains.uast.visitor.UastVisitor;
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
"LocalSuppress", //$NON-NLS-1$
|
||||
@@ -94,59 +79,45 @@ public class AnnotationDetector extends Detector implements Detector.JavaScanner
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
||||
return Collections.<Class<? extends Node>>singletonList(Annotation.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
||||
public UastVisitor createUastVisitor(UastAndroidContext context) {
|
||||
return new AnnotationChecker(context);
|
||||
}
|
||||
|
||||
private static class AnnotationChecker extends ForwardingAstVisitor {
|
||||
private final JavaContext mContext;
|
||||
private static class AnnotationChecker extends UastVisitor {
|
||||
private final UastAndroidContext mContext;
|
||||
|
||||
public AnnotationChecker(JavaContext context) {
|
||||
public AnnotationChecker(UastAndroidContext context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitAnnotation(Annotation node) {
|
||||
String type = node.astAnnotationTypeReference().getTypeName();
|
||||
public boolean visitAnnotation(@NotNull UAnnotation node) {
|
||||
String type = node.getName();
|
||||
if (SUPPRESS_LINT.equals(type) || FQCN_SUPPRESS_LINT.equals(type)) {
|
||||
Node parent = node.getParent();
|
||||
if (parent instanceof Modifiers) {
|
||||
parent = parent.getParent();
|
||||
if (parent instanceof VariableDefinition) {
|
||||
for (AnnotationElement element : node.astElements()) {
|
||||
AnnotationValue valueNode = element.astValue();
|
||||
if (valueNode == null) {
|
||||
UElement parent = node.getParent();
|
||||
if (parent instanceof UVariable) {
|
||||
for (UNamedExpression element : node.getValueArguments()) {
|
||||
UExpression valueNode = element.getExpression();
|
||||
if (UastLiteralUtils.isStringLiteral(valueNode)) {
|
||||
ULiteralExpression literal = (ULiteralExpression) valueNode;
|
||||
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;
|
||||
}
|
||||
if (valueNode instanceof StringLiteral) {
|
||||
StringLiteral literal = (StringLiteral) valueNode;
|
||||
String id = literal.astValue();
|
||||
if (!checkId(node, id)) {
|
||||
return super.visitAnnotation(node);
|
||||
}
|
||||
} else if (valueNode instanceof ArrayInitializer) {
|
||||
ArrayInitializer array = (ArrayInitializer) valueNode;
|
||||
StrictListAccessor<Expression, ArrayInitializer> expressions =
|
||||
array.astExpressions();
|
||||
if (expressions == null) {
|
||||
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);
|
||||
}
|
||||
for (UExpression arrayElement : array.getValueArguments()) {
|
||||
if (UastLiteralUtils.isStringLiteral(arrayElement)) {
|
||||
String id = ((String)((ULiteralExpression)arrayElement).getValue());
|
||||
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) {
|
||||
IssueRegistry registry = mContext.getDriver().getRegistry();
|
||||
private boolean checkId(UAnnotation node, String id) {
|
||||
IssueRegistry registry = mContext.getLintContext().getDriver().getRegistry();
|
||||
Issue issue = registry.getIssue(id);
|
||||
// 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
|
||||
// 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) {
|
||||
// Ensure that this isn't a field
|
||||
Node parent = node.getParent();
|
||||
UElement parent = node.getParent();
|
||||
while (parent != null) {
|
||||
if (parent instanceof MethodDeclaration
|
||||
|| parent instanceof ConstructorDeclaration
|
||||
|| parent instanceof Block) {
|
||||
if (parent instanceof UFunction || parent instanceof UBlockExpression) {
|
||||
break;
|
||||
} else if (parent instanceof TypeBody) { // It's a field
|
||||
return true;
|
||||
} else if (issue == ApiDetector.UNSUPPORTED
|
||||
&& parent instanceof VariableDefinition) {
|
||||
VariableDefinition definition = (VariableDefinition) parent;
|
||||
for (VariableDefinitionEntry entry : definition.astVariables()) {
|
||||
Expression initializer = entry.astInitializer();
|
||||
if (initializer instanceof Select) {
|
||||
} else if (issue == ApiDetector.UNSUPPORTED && parent instanceof UDeclarationsExpression) {
|
||||
UDeclarationsExpression declarations = (UDeclarationsExpression)parent;
|
||||
for (UVariable var : declarations.getVariables()) {
|
||||
if (var.getKind() != UastVariableKind.MEMBER && var.getInitializer() instanceof UQualifiedExpression) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -193,7 +158,7 @@ public class AnnotationDetector extends Detector implements Detector.JavaScanner
|
||||
|
||||
// This issue doesn't have AST access: annotations are not
|
||||
// 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 " +
|
||||
"variable with the lint check '%1$s': move out to the " +
|
||||
"surrounding method", id));
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
import static com.android.SdkConstants.CONSTRUCTOR_NAME;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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_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.CONSTRUCTOR_NAME;
|
||||
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.TAG;
|
||||
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.TOOLS_URI;
|
||||
import static com.android.SdkConstants.VIEW_TAG;
|
||||
import static com.android.tools.lint.detector.api.ClassContext.getFqcn;
|
||||
import static com.android.tools.lint.detector.api.ClassContext.getInternalName;
|
||||
import static com.android.tools.lint.detector.api.LintUtils.getNextInstruction;
|
||||
import static com.android.tools.lint.detector.api.Location.SearchDirection.BACKWARD;
|
||||
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.tools.klint.detector.api.LintUtils.getNextInstruction;
|
||||
import static com.android.tools.klint.detector.api.Location.SearchDirection.BACKWARD;
|
||||
import static com.android.tools.klint.detector.api.Location.SearchDirection.FORWARD;
|
||||
import static com.android.tools.klint.detector.api.Location.SearchDirection.NEAREST;
|
||||
import static com.android.utils.SdkUtils.getResourceFieldName;
|
||||
|
||||
import com.android.SdkConstants;
|
||||
@@ -56,32 +53,27 @@ import com.android.annotations.Nullable;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.sdklib.AndroidVersion;
|
||||
import com.android.sdklib.SdkVersionInfo;
|
||||
import com.android.tools.lint.client.api.IssueRegistry;
|
||||
import com.android.tools.lint.client.api.JavaParser;
|
||||
import com.android.tools.lint.client.api.LintDriver;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.ClassContext;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.DefaultPosition;
|
||||
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.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Location.SearchHints;
|
||||
import com.android.tools.lint.detector.api.Position;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.TextFormat;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.client.api.IssueRegistry;
|
||||
import com.android.tools.klint.client.api.LintDriver;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.ClassContext;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Location.SearchHints;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.detector.api.TextFormat;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
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.Type;
|
||||
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.InsnList;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.LocalVariableNode;
|
||||
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.analysis.AnalyzerException;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
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
|
||||
* by this application (according to its minimum API requirement in the manifest).
|
||||
*/
|
||||
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
|
||||
@@ -1386,9 +1343,9 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
super.afterCheckProject(context);
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Nullable
|
||||
/* @Nullable
|
||||
@Override
|
||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
||||
if (mApiDatabase == null) {
|
||||
@@ -1413,7 +1370,7 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
*//**
|
||||
* 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}.
|
||||
*
|
||||
@@ -1422,7 +1379,18 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
* @param owner the field owner
|
||||
* @return true if the given usage is safe on older versions than the introduction
|
||||
* level of the constant
|
||||
*/
|
||||
*//*
|
||||
|
||||
*/
|
||||
|
||||
public static boolean isBenignConstantUsage(
|
||||
@Nullable UElement node,
|
||||
@NonNull String name,
|
||||
@NonNull String owner) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
public static boolean isBenignConstantUsage(
|
||||
@Nullable lombok.ast.Node node,
|
||||
@NonNull String name,
|
||||
@@ -1811,10 +1779,10 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
super.endVisit(node);
|
||||
}
|
||||
|
||||
/**
|
||||
*//**
|
||||
* Checks a Java source field reference. Returns true if the field is known
|
||||
* regardless of whether it's an invalid field or not
|
||||
*/
|
||||
*//*
|
||||
private boolean checkField(
|
||||
@NonNull lombok.ast.Node node,
|
||||
@NonNull String name,
|
||||
@@ -1902,12 +1870,12 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*//**
|
||||
* Returns the minimum SDK to use according to the given AST node, or null
|
||||
* if no {@code TargetApi} annotations were found
|
||||
*
|
||||
* @return the API level to use for this node, or -1
|
||||
*/
|
||||
*//*
|
||||
public int getLocalMinSdk(@Nullable lombok.ast.Node scope) {
|
||||
while (scope != null) {
|
||||
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
|
||||
* an {@code @TargetApi} annotation.
|
||||
*
|
||||
* @param modifiers the modifier to check
|
||||
* @return the target API level, or -1 if not specified
|
||||
*/
|
||||
*//*
|
||||
public static int getTargetApi(@Nullable Modifiers modifiers) {
|
||||
if (modifiers == null) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2023,7 +2021,7 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
@NonNull ClassNode classNode,
|
||||
@NonNull MethodNode method,
|
||||
@NonNull AbstractInsnNode call,
|
||||
int requiredApi) {
|
||||
int requiredApi) { return false; } /*
|
||||
assert requiredApi != -1;
|
||||
|
||||
if (!containsSimpleSdkCheck(method)) {
|
||||
@@ -2126,10 +2124,10 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*//**
|
||||
* Control flow graph which skips control flow edges that check
|
||||
* a given SDK_VERSION requirement that is not met by a given call
|
||||
*/
|
||||
*//*
|
||||
private static class ApiCheckGraph extends ControlFlowGraph {
|
||||
private final int mRequiredApi;
|
||||
|
||||
@@ -2177,5 +2175,5 @@ public class ApiDetector extends ResourceXmlDetector
|
||||
|
||||
super.add(from, to);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.DOT_XML;
|
||||
@@ -26,8 +26,8 @@ import com.android.sdklib.repository.FullRevision;
|
||||
import com.android.sdklib.repository.descriptors.PkgType;
|
||||
import com.android.sdklib.repository.local.LocalPkgInfo;
|
||||
import com.android.sdklib.repository.local.LocalSdk;
|
||||
import com.android.tools.lint.client.api.LintClient;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.client.api.LintClient;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
+38
-47
@@ -13,37 +13,37 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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.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.Nullable;
|
||||
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.JavaParser.ResolvedNode;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.JavaContext;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
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 com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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.LintUtils;
|
||||
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 com.android.tools.klint.detector.api.TextFormat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.ClassDeclaration;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import org.jetbrains.uast.UCallExpression;
|
||||
import org.jetbrains.uast.UClass;
|
||||
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(
|
||||
"AppCompatMethod",
|
||||
"Using Wrong AppCompat Method",
|
||||
@@ -82,23 +82,21 @@ public class AppCompatCallDetector extends Detector implements Detector.JavaScan
|
||||
mDependsOnAppCompat = dependsOnAppCompat != null && dependsOnAppCompat;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Arrays.asList(
|
||||
GET_ACTION_BAR,
|
||||
START_ACTION_MODE,
|
||||
SET_PROGRESS_BAR_VIS,
|
||||
SET_PROGRESS_BAR_IN_VIS,
|
||||
SET_PROGRESS_BAR_INDETERMINATE,
|
||||
REQUEST_WINDOW_FEATURE);
|
||||
GET_ACTION_BAR,
|
||||
START_ACTION_MODE,
|
||||
SET_PROGRESS_BAR_VIS,
|
||||
SET_PROGRESS_BAR_IN_VIS,
|
||||
SET_PROGRESS_BAR_INDETERMINATE,
|
||||
REQUEST_WINDOW_FEATURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation node) {
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
if (mDependsOnAppCompat && isAppBarActivityCall(context, node)) {
|
||||
String name = node.astName().astValue();
|
||||
String name = node.getFunctionName();
|
||||
String replace = null;
|
||||
if (GET_ACTION_BAR.equals(name)) {
|
||||
replace = "getSupportActionBar";
|
||||
@@ -116,29 +114,22 @@ public class AppCompatCallDetector extends Detector implements Detector.JavaScan
|
||||
|
||||
if (replace != null) {
|
||||
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,
|
||||
@NonNull MethodInvocation node) {
|
||||
ResolvedNode resolved = context.resolve(node);
|
||||
if (resolved instanceof ResolvedMethod) {
|
||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
||||
ResolvedClass containingClass = method.getContainingClass();
|
||||
if (containingClass.isSubclassOf(CLASS_ACTIVITY, false)) {
|
||||
private static boolean isAppBarActivityCall(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression node) {
|
||||
UFunction resolved = node.resolve(context);
|
||||
if (resolved != null) {
|
||||
UClass containingClass = UastUtils.getContainingClass(resolved);
|
||||
if (containingClass != null && containingClass.isSubclassOf(CLASS_ACTIVITY)) {
|
||||
// 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
|
||||
// such as PreferenceActivity (see b.android.com/58512)
|
||||
ClassDeclaration surroundingClass = JavaContext.findSurroundingClass(node);
|
||||
if (surroundingClass != null) {
|
||||
ResolvedNode clz = context.resolve(surroundingClass);
|
||||
return clz instanceof ResolvedClass &&
|
||||
((ResolvedClass)clz).isSubclassOf(
|
||||
"android.support.v7.app.ActionBarActivity",
|
||||
false);
|
||||
}
|
||||
return UastUtils.getContainingClassOrEmpty(node)
|
||||
.isSubclassOf("android.support.v7.app.ActionBarActivity");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
+12
-12
@@ -14,24 +14,24 @@
|
||||
* 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.ATTR_SHOW_AS_ACTION;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
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.Project;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
import org.w3c.dom.Attr;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -43,7 +43,7 @@ import java.util.Collections;
|
||||
* 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.
|
||||
*/
|
||||
public class AppCompatResourceDetector extends ResourceXmlDetector implements JavaScanner {
|
||||
public class AppCompatResourceDetector extends ResourceXmlDetector implements UastScanner {
|
||||
/** The main issue discovered by this detector */
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
"AppCompatResource", //$NON-NLS-1$
|
||||
|
||||
+10
-10
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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.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.resources.ResourceUrl;
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.tools.lint.client.api.LintClient;
|
||||
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.Project;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.client.api.LintClient;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
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.Project;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
+14
-14
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
|
||||
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.resources.ResourceFolderType;
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.tools.lint.client.api.LintClient;
|
||||
import com.android.tools.lint.client.api.LintDriver;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.client.api.LintClient;
|
||||
import com.android.tools.klint.client.api.LintDriver;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.android.utils.Pair;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
@@ -14,35 +14,33 @@
|
||||
* 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.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.JavaContext;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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 java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.Assert;
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.BinaryExpression;
|
||||
import lombok.ast.BooleanLiteral;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.ForwardingAstVisitor;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.NullLiteral;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
import org.jetbrains.uast.java.JavaSpecialExpressionKinds;
|
||||
import org.jetbrains.uast.visitor.UastVisitor;
|
||||
|
||||
import static org.jetbrains.uast.UastLiteralUtils.isNullLiteral;
|
||||
|
||||
/**
|
||||
* Looks for assertion usages.
|
||||
*/
|
||||
public class AssertDetector extends Detector implements Detector.JavaScanner {
|
||||
public class AssertDetector extends Detector implements UastScanner {
|
||||
/** Using assertions */
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
"Assert", //$NON-NLS-1$
|
||||
@@ -80,28 +78,30 @@ public class AssertDetector extends Detector implements Detector.JavaScanner {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
||||
return Collections.<Class<? extends Node>>singletonList(Assert.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AstVisitor createJavaVisitor(@NonNull final JavaContext context) {
|
||||
return new ForwardingAstVisitor() {
|
||||
public UastVisitor createUastVisitor(final UastAndroidContext context) {
|
||||
return new UastVisitor() {
|
||||
@Override
|
||||
public boolean visitAssert(Assert node) {
|
||||
if (!context.getMainProject().isAndroidProject()) {
|
||||
public boolean visitSpecialExpressionList(@NotNull USpecialExpressionList node) {
|
||||
if (node.getKind() != JavaSpecialExpressionKinds.ASSERT) {
|
||||
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
|
||||
if (assertion instanceof BooleanLiteral) {
|
||||
Boolean b = ((BooleanLiteral) assertion).astValue();
|
||||
if (b != null && b) {
|
||||
return false;
|
||||
if (assertion instanceof ULiteralExpression) {
|
||||
ULiteralExpression literal = (ULiteralExpression) assertion;
|
||||
if (literal.isBoolean()) {
|
||||
Boolean b = ((Boolean)literal.getValue());
|
||||
if (b != null && b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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
|
||||
= "Assertions are unreliable. Use `BuildConfig.DEBUG` conditional checks instead.";
|
||||
context.report(ISSUE, node, context.getLocation(node), message);
|
||||
= "Assertions are unreliable. Use `BuildConfig.DEBUG` conditional checks instead.";
|
||||
context.report(ISSUE, node, UastAndroidUtils.getLocation(node), message);
|
||||
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
|
||||
* "b == null || c != null".
|
||||
*/
|
||||
private static boolean isNullCheck(Expression expression) {
|
||||
if (expression instanceof BinaryExpression) {
|
||||
BinaryExpression binExp = (BinaryExpression) expression;
|
||||
if (binExp.astLeft() instanceof NullLiteral ||
|
||||
binExp.astRight() instanceof NullLiteral) {
|
||||
private static boolean isNullCheck(UExpression expression) {
|
||||
if (expression instanceof UBinaryExpression) {
|
||||
UBinaryExpression binExp = (UBinaryExpression) expression;
|
||||
if (isNullLiteral(binExp.getLeftOperand()) ||
|
||||
isNullLiteral(binExp.getRightOperand())) {
|
||||
return true;
|
||||
} else {
|
||||
return isNullCheck(binExp.astLeft()) && isNullCheck(binExp.astRight());
|
||||
return isNullCheck(binExp.getLeftOperand()) && isNullCheck(binExp.getRightOperand());
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
+5
-5
@@ -14,13 +14,13 @@
|
||||
* 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.VisibleForTesting;
|
||||
import com.android.tools.lint.client.api.IssueRegistry;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.klint.client.api.IssueRegistry;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -283,7 +283,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
|
||||
initialSize += 10;
|
||||
}
|
||||
|
||||
if (scope.contains(Scope.JAVA_FILE)) {
|
||||
if (scope.contains(Scope.SOURCE_FILE)) {
|
||||
initialSize += 55;
|
||||
} else if (scope.contains(Scope.CLASS_FILE)) {
|
||||
initialSize += 15;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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_URI;
|
||||
@@ -41,17 +41,17 @@ import static com.android.SdkConstants.VALUE_VERTICAL;
|
||||
import com.android.SdkConstants;
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
+10
-10
@@ -14,21 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
import static com.android.SdkConstants.ATTR_NAME;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
|
||||
|
||||
+70
-81
@@ -14,42 +14,37 @@
|
||||
* 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.SUPPORT_ANNOTATIONS_PREFIX;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.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 com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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.Location;
|
||||
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 java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.ForwardingAstVisitor;
|
||||
import lombok.ast.MethodDeclaration;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.Super;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
import org.jetbrains.uast.visitor.UastVisitor;
|
||||
|
||||
/**
|
||||
* 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 ON_DETACHED_FROM_WINDOW = "onDetachedFromWindow"; //$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;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
||||
return Collections.<Class<? extends Node>>singletonList(MethodDeclaration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AstVisitor createJavaVisitor(@NonNull final JavaContext context) {
|
||||
return new ForwardingAstVisitor() {
|
||||
public UastVisitor createUastVisitor(final UastAndroidContext context) {
|
||||
return new UastVisitor() {
|
||||
@Override
|
||||
public boolean visitMethodDeclaration(MethodDeclaration node) {
|
||||
ResolvedNode resolved = context.resolve(node);
|
||||
if (resolved instanceof ResolvedMethod) {
|
||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
||||
checkCallSuper(context, node, method);
|
||||
}
|
||||
|
||||
public boolean visitFunction(@NotNull UFunction node) {
|
||||
checkCallSuper(context, node);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void checkCallSuper(@NonNull JavaContext context,
|
||||
@NonNull MethodDeclaration declaration,
|
||||
@NonNull ResolvedMethod method) {
|
||||
private static void checkCallSuper(@NonNull UastAndroidContext context,
|
||||
@NonNull UFunction declaration) {
|
||||
|
||||
ResolvedMethod superMethod = getRequiredSuperMethod(method);
|
||||
UFunction superMethod = getRequiredSuperMethod(context, declaration);
|
||||
if (superMethod != null) {
|
||||
if (!SuperCallVisitor.callsSuper(context, declaration, superMethod)) {
|
||||
String methodName = method.getName();
|
||||
String methodName = declaration.getName();
|
||||
String message = "Overriding method should call `super."
|
||||
+ methodName + "`";
|
||||
Location location = context.getLocation(declaration.astMethodName());
|
||||
Location location = UastAndroidUtils.getLocation(declaration.getNameElement());
|
||||
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)
|
||||
*/
|
||||
@Nullable
|
||||
private static ResolvedMethod getRequiredSuperMethod(
|
||||
@NonNull ResolvedMethod method) {
|
||||
private static UFunction getRequiredSuperMethod(UastAndroidContext context,
|
||||
@NonNull UFunction method) {
|
||||
|
||||
String name = method.getName();
|
||||
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
|
||||
// this for now (should make annotation carry metadata like
|
||||
// compileSdkVersion >= N).
|
||||
if (!method.getContainingClass().isSubclassOf(CLASS_VIEW, false)) {
|
||||
if (!UastUtils.getContainingClassOrEmpty(method).isSubclassOf(CLASS_VIEW)) {
|
||||
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)) {
|
||||
// From Android Wear API; doesn't yet have an annotation
|
||||
// but we want to enforce this right away until the AAR
|
||||
// is updated to supply it once @CallSuper is available in
|
||||
// the support library
|
||||
if (!method.getContainingClass().isSubclassOf(
|
||||
"android.support.wearable.watchface.WatchFaceService.Engine", false)) {
|
||||
if (!UastUtils.getContainingClassOrEmpty(method).isSubclassOf(
|
||||
"android.support.wearable.watchface.WatchFaceService.Engine")) {
|
||||
return null;
|
||||
}
|
||||
return method.getSuperMethod();
|
||||
List<UFunction> superFunctions = method.getSuperFunctions(context);
|
||||
return superFunctions.isEmpty() ? null : superFunctions.get(0);
|
||||
}
|
||||
|
||||
// Look up annotations metadata
|
||||
ResolvedMethod directSuper = method.getSuperMethod();
|
||||
ResolvedMethod superMethod = directSuper;
|
||||
List<UFunction> superFunctions = method.getSuperFunctions(context);
|
||||
UFunction directSuper = superFunctions.isEmpty() ? null : superFunctions.get(0);
|
||||
UFunction superMethod = directSuper;
|
||||
while (superMethod != null) {
|
||||
Iterable<JavaParser.ResolvedAnnotation> annotations = superMethod.getAnnotations();
|
||||
for (JavaParser.ResolvedAnnotation annotation : annotations) {
|
||||
annotation = SupportAnnotationDetector.getRelevantAnnotation(annotation);
|
||||
for (UAnnotation annotation : superMethod.getAnnotations()) {
|
||||
annotation = SupportAnnotationDetector.getRelevantAnnotation(context, annotation);
|
||||
if (annotation != null) {
|
||||
String signature = annotation.getSignature();
|
||||
String signature = annotation.getFqName();
|
||||
if (CALL_SUPER_ANNOTATION.equals(signature)) {
|
||||
return directSuper;
|
||||
} else if (signature.endsWith(".OverrideMustInvoke")) {
|
||||
} else if (signature != null && signature.endsWith(".OverrideMustInvoke")) {
|
||||
// Handle findbugs annotation on the fly too
|
||||
return directSuper;
|
||||
}
|
||||
}
|
||||
}
|
||||
superMethod = superMethod.getSuperMethod();
|
||||
superFunctions = superMethod.getSuperFunctions(context);
|
||||
superMethod = superFunctions.isEmpty() ? null : superFunctions.get(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Visits a method and determines whether the method calls its super method */
|
||||
private static class SuperCallVisitor extends ForwardingAstVisitor {
|
||||
private final JavaContext mContext;
|
||||
private final ResolvedMethod mMethod;
|
||||
private static class SuperCallVisitor extends UastVisitor {
|
||||
private final UastAndroidContext mContext;
|
||||
private final String mMethodFqName;
|
||||
private boolean mCallsSuper;
|
||||
|
||||
public static boolean callsSuper(
|
||||
@NonNull JavaContext context,
|
||||
@NonNull MethodDeclaration methodDeclaration,
|
||||
@NonNull ResolvedMethod method) {
|
||||
SuperCallVisitor visitor = new SuperCallVisitor(context, method);
|
||||
methodDeclaration.accept(visitor);
|
||||
@NonNull UastAndroidContext context,
|
||||
@NonNull UFunction methodDeclaration,
|
||||
@NonNull UFunction superMethod) {
|
||||
SuperCallVisitor visitor = new SuperCallVisitor(context, superMethod);
|
||||
visitor.process(methodDeclaration);
|
||||
return visitor.mCallsSuper;
|
||||
}
|
||||
|
||||
private SuperCallVisitor(@NonNull JavaContext context, @NonNull ResolvedMethod method) {
|
||||
private SuperCallVisitor(@NonNull UastAndroidContext context, @NonNull UFunction method) {
|
||||
mContext = context;
|
||||
mMethod = method;
|
||||
mMethodFqName = UastUtils.getFqName(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitSuper(Super node) {
|
||||
ResolvedNode resolved = null;
|
||||
if (node.getParent() instanceof MethodInvocation) {
|
||||
resolved = mContext.resolve(node.getParent());
|
||||
}
|
||||
if (resolved == null) {
|
||||
resolved = mContext.resolve(node);
|
||||
}
|
||||
if (mMethod.equals(resolved)) {
|
||||
mCallsSuper = true;
|
||||
return true;
|
||||
public boolean visitQualifiedExpression(@NotNull UQualifiedExpression node) {
|
||||
UExpression receiver = node.getReceiver();
|
||||
UExpression selector = node.getSelector();
|
||||
|
||||
if (receiver instanceof USuperExpression && selector instanceof UCallExpression) {
|
||||
UFunction resolvedFunction = ((UCallExpression) selector).resolve(mContext);
|
||||
if (mMethodFqName.equals(UastUtils.getFqName(resolvedFunction))) {
|
||||
mCallsSuper = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(Node node) {
|
||||
return mCallsSuper || super.visitNode(node);
|
||||
public void process(@NotNull UElement element) {
|
||||
if (!mCallsSuper) {
|
||||
super.process(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -14,7 +14,7 @@
|
||||
* 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.HORIZONTAL_SCROLL_VIEW;
|
||||
@@ -23,15 +23,15 @@ import static com.android.SdkConstants.REQUEST_FOCUS;
|
||||
import static com.android.SdkConstants.SCROLL_VIEW;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
+40
-48
@@ -14,36 +14,31 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser;
|
||||
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 com.android.tools.klint.detector.api.Category;
|
||||
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 com.google.common.collect.Sets;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.StrictListAccessor;
|
||||
import lombok.ast.StringLiteral;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
|
||||
/**
|
||||
* 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(
|
||||
"GetInstance", //$NON-NLS-1$
|
||||
"Cipher.getInstance with ECB",
|
||||
@@ -69,59 +64,56 @@ public class CipherGetInstanceDetector extends Detector implements Detector.Java
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Collections.singletonList(GET_INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation node) {
|
||||
// Ignore if the method doesn't fit our description.
|
||||
JavaParser.ResolvedNode resolved = context.resolve(node);
|
||||
if (!(resolved instanceof JavaParser.ResolvedMethod)) {
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
UClass containingClass = UastUtils.getContainingClass(node);
|
||||
if (containingClass == null || !containingClass.isSubclassOf(CIPHER)) {
|
||||
return;
|
||||
}
|
||||
JavaParser.ResolvedMethod method = (JavaParser.ResolvedMethod) resolved;
|
||||
if (!method.getContainingClass().isSubclassOf(CIPHER, false)) {
|
||||
return;
|
||||
}
|
||||
StrictListAccessor<Expression, MethodInvocation> argumentList = node.astArguments();
|
||||
if (argumentList != null && argumentList.size() == 1) {
|
||||
Expression expression = argumentList.first();
|
||||
if (expression instanceof StringLiteral) {
|
||||
StringLiteral argument = (StringLiteral)expression;
|
||||
String parameter = argument.astValue();
|
||||
|
||||
List<UExpression> argumentList = node.getValueArguments();
|
||||
if (argumentList.size() == 1) {
|
||||
UExpression expression = argumentList.get(0);
|
||||
if (expression instanceof ULiteralExpression) {
|
||||
ULiteralExpression argument = (ULiteralExpression)expression;
|
||||
String parameter = argument.getText();
|
||||
checkParameter(context, node, argument, parameter, false);
|
||||
} else {
|
||||
JavaParser.ResolvedNode resolve = context.resolve(expression);
|
||||
if (resolve instanceof JavaParser.ResolvedField) {
|
||||
JavaParser.ResolvedField field = (JavaParser.ResolvedField) resolve;
|
||||
Object value = field.getValue();
|
||||
if (value instanceof String) {
|
||||
checkParameter(context, node, expression, (String)value, true);
|
||||
} else if (expression instanceof UResolvable) {
|
||||
UDeclaration declaration = ((UResolvable)expression).resolve(context);
|
||||
if (declaration instanceof UVariable) {
|
||||
UVariable field = (UVariable) declaration;
|
||||
UExpression initializer = field.getInitializer();
|
||||
if (initializer != null) {
|
||||
Object value = initializer.evaluate();
|
||||
if (value instanceof String) {
|
||||
checkParameter(context, node, expression, (String)value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkParameter(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation call, @NonNull Node node, @NonNull String value,
|
||||
boolean includeValue) {
|
||||
private static void checkParameter(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression call, @NonNull UExpression arg, @NonNull String value,
|
||||
boolean includeValue) {
|
||||
if (ALGORITHM_ONLY.contains(value)) {
|
||||
String message = "`Cipher.getInstance` should not be called without setting the"
|
||||
+ " 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)) {
|
||||
String message = "ECB encryption mode should not be used";
|
||||
if (includeValue) {
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
import static com.android.SdkConstants.CLASS_CONTEXT;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedField;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedVariable;
|
||||
import com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
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.android.tools.klint.detector.api.Category;
|
||||
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.Location;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.BinaryExpression;
|
||||
import lombok.ast.BinaryOperator;
|
||||
import lombok.ast.ConstructorInvocation;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.ForwardingAstVisitor;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.Return;
|
||||
import lombok.ast.StrictListAccessor;
|
||||
import lombok.ast.VariableDefinitionEntry;
|
||||
import lombok.ast.VariableReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
import org.jetbrains.uast.visitor.UastVisitor;
|
||||
|
||||
/**
|
||||
* Checks for missing {@code recycle} calls on resources that encourage it, and
|
||||
* 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(
|
||||
CleanupDetector.class,
|
||||
@@ -140,26 +126,26 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
public CleanupDetector() {
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Arrays.asList(
|
||||
// FragmentManager commit check
|
||||
BEGIN_TRANSACTION,
|
||||
// FragmentManager commit check
|
||||
BEGIN_TRANSACTION,
|
||||
|
||||
// Recycle check
|
||||
OBTAIN, OBTAIN_NO_HISTORY,
|
||||
OBTAIN_STYLED_ATTRIBUTES,
|
||||
OBTAIN_ATTRIBUTES,
|
||||
OBTAIN_TYPED_ARRAY,
|
||||
// Recycle check
|
||||
OBTAIN, OBTAIN_NO_HISTORY,
|
||||
OBTAIN_STYLED_ATTRIBUTES,
|
||||
OBTAIN_ATTRIBUTES,
|
||||
OBTAIN_TYPED_ARRAY,
|
||||
|
||||
// Release check
|
||||
ACQUIRE_CPC,
|
||||
// Release check
|
||||
ACQUIRE_CPC,
|
||||
|
||||
// Cursor close check
|
||||
QUERY, RAW_QUERY, QUERY_WITH_FACTORY, RAW_QUERY_WITH_FACTORY
|
||||
// Cursor close check
|
||||
QUERY, RAW_QUERY, QUERY_WITH_FACTORY, RAW_QUERY_WITH_FACTORY
|
||||
);
|
||||
}
|
||||
|
||||
@@ -170,10 +156,8 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation node) {
|
||||
|
||||
String name = node.astName().astValue();
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
String name = node.getFunctionName();
|
||||
if (BEGIN_TRANSACTION.equals(name)) {
|
||||
checkTransactionCommits(context, node);
|
||||
} else {
|
||||
@@ -182,48 +166,53 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConstructor(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull ConstructorInvocation node, @NonNull ResolvedMethod constructor) {
|
||||
checkRecycled(context, node, constructor.getContainingClass().getSignature(), RELEASE);
|
||||
public void visitConstructor(UastAndroidContext context, UCallExpression functionCall, UFunction constructor) {
|
||||
UClass containingClass = UastUtils.getContainingClass(constructor);
|
||||
if (containingClass != null) {
|
||||
checkRecycled(context, functionCall, containingClass.getFqName(), RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkResourceRecycled(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation node, @NonNull String name) {
|
||||
private static void checkResourceRecycled(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression node, @NonNull String name) {
|
||||
// Recycle detector
|
||||
ResolvedNode resolved = context.resolve(node);
|
||||
if (!(resolved instanceof ResolvedMethod)) {
|
||||
UFunction method = node.resolve(context);
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
||||
ResolvedClass containingClass = method.getContainingClass();
|
||||
UClass containingClass = UastUtils.getContainingClass(method);
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
} 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);
|
||||
} else if (OBTAIN.equals(name) &&
|
||||
containingClass.isSubclassOf(VELOCITY_TRACKER_CLS, false)) {
|
||||
containingClass.isSubclassOf(VELOCITY_TRACKER_CLS)) {
|
||||
checkRecycled(context, node, VELOCITY_TRACKER_CLS, RECYCLE);
|
||||
} else if ((OBTAIN_STYLED_ATTRIBUTES.equals(name)
|
||||
|| OBTAIN_ATTRIBUTES.equals(name)
|
||||
|| OBTAIN_TYPED_ARRAY.equals(name)) &&
|
||||
(containingClass.isSubclassOf(CLASS_CONTEXT, false) ||
|
||||
containingClass.isSubclassOf(RESOURCES_CLS, false))) {
|
||||
TypeDescriptor returnType = method.getReturnType();
|
||||
if (returnType != null && returnType.matchesSignature(TYPED_ARRAY_CLS)) {
|
||||
(containingClass.isSubclassOf(CLASS_CONTEXT) ||
|
||||
containingClass.isSubclassOf(RESOURCES_CLS))) {
|
||||
UType returnType = method.getReturnType();
|
||||
if (returnType != null && returnType.matchesFqName(TYPED_ARRAY_CLS)) {
|
||||
checkRecycled(context, node, TYPED_ARRAY_CLS, RECYCLE);
|
||||
}
|
||||
} else if (ACQUIRE_CPC.equals(name) && containingClass.isSubclassOf(
|
||||
CONTENT_RESOLVER_CLS, false)) {
|
||||
CONTENT_RESOLVER_CLS)) {
|
||||
checkRecycled(context, node, CONTENT_PROVIDER_CLIENT_CLS, RELEASE);
|
||||
} else if ((QUERY.equals(name)
|
||||
|| RAW_QUERY.equals(name)
|
||||
|| QUERY_WITH_FACTORY.equals(name)
|
||||
|| RAW_QUERY_WITH_FACTORY.equals(name))
|
||||
&& (containingClass.isSubclassOf(SQLITE_DATABASE_CLS, false) ||
|
||||
containingClass.isSubclassOf(CONTENT_RESOLVER_CLS, false) ||
|
||||
containingClass.isSubclassOf(CONTENT_PROVIDER_CLS, false) ||
|
||||
containingClass.isSubclassOf(CONTENT_PROVIDER_CLIENT_CLS, false))) {
|
||||
&& (containingClass.isSubclassOf(SQLITE_DATABASE_CLS) ||
|
||||
containingClass.isSubclassOf(CONTENT_RESOLVER_CLS) ||
|
||||
containingClass.isSubclassOf(CONTENT_PROVIDER_CLS) ||
|
||||
containingClass.isSubclassOf(CONTENT_PROVIDER_CLIENT_CLS))) {
|
||||
// Other potential cursors-returning methods that should be tracked:
|
||||
// android.app.DownloadManager#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) {
|
||||
ResolvedVariable boundVariable = getVariable(context, node);
|
||||
UVariable boundVariable = getVariable(context, node);
|
||||
if (boundVariable == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node method = JavaContext.findSurroundingMethod(node);
|
||||
UFunction method = UastUtils.getContainingFunction(node);
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FinishVisitor visitor = new FinishVisitor(context, boundVariable) {
|
||||
@Override
|
||||
protected boolean isCleanupCall(@NonNull MethodInvocation call) {
|
||||
String methodName = call.astName().astValue();
|
||||
protected boolean isCleanupCall(@NonNull UCallExpression call) {
|
||||
String methodName = call.getFunctionName();
|
||||
if (!recycleName.equals(methodName)) {
|
||||
return false;
|
||||
}
|
||||
ResolvedNode resolved = mContext.resolve(call);
|
||||
if (resolved instanceof ResolvedMethod) {
|
||||
ResolvedClass containingClass = ((ResolvedMethod) resolved).getContainingClass();
|
||||
if (containingClass.isSubclassOf(recycleType, false)) {
|
||||
UDeclaration resolved = call.resolve(mContext);
|
||||
if (resolved != null) {
|
||||
UClass containingClass = UastUtils.getContainingClassOrEmpty(resolved);
|
||||
if (containingClass.isSubclassOf(recycleType)) {
|
||||
// Yes, called the right recycle() method; now make sure
|
||||
// we're calling it on the right variable
|
||||
Expression operand = call.astOperand();
|
||||
if (operand != null) {
|
||||
resolved = mContext.resolve(operand);
|
||||
UElement parent = call.getParent();
|
||||
if (parent instanceof UQualifiedExpression) {
|
||||
UExpression operand = ((UQualifiedExpression) parent).getReceiver();
|
||||
resolved = UastUtils.resolveIfCan(operand, mContext);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
return true;
|
||||
@@ -281,7 +271,7 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
};
|
||||
|
||||
method.accept(visitor);
|
||||
visitor.process(method);
|
||||
if (visitor.isCleanedUp() || visitor.variableEscapes()) {
|
||||
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,
|
||||
recycleName);
|
||||
}
|
||||
Node locationNode = node instanceof MethodInvocation ?
|
||||
((MethodInvocation) node).astName() : node;
|
||||
Location location = context.getLocation(locationNode);
|
||||
UElement locationNode = node instanceof UCallExpression ?
|
||||
((UCallExpression) node).getFunctionNameElement() : node;
|
||||
Location location = UastAndroidUtils.getLocation(locationNode);
|
||||
context.report(RECYCLE_RESOURCE, node, location, message);
|
||||
}
|
||||
|
||||
private static boolean checkTransactionCommits(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation node) {
|
||||
private static boolean checkTransactionCommits(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression node) {
|
||||
if (isBeginTransaction(context, node)) {
|
||||
ResolvedVariable boundVariable = getVariable(context, node);
|
||||
UVariable boundVariable = getVariable(context, node);
|
||||
if (boundVariable == null && isCommittedInChainedCalls(context, node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (boundVariable != null) {
|
||||
Node method = JavaContext.findSurroundingMethod(node);
|
||||
UFunction method = UastUtils.getContainingFunction(node);
|
||||
if (method == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FinishVisitor commitVisitor = new FinishVisitor(context, boundVariable) {
|
||||
@Override
|
||||
protected boolean isCleanupCall(@NonNull MethodInvocation call) {
|
||||
protected boolean isCleanupCall(@NonNull UCallExpression call) {
|
||||
if (isTransactionCommitMethodCall(mContext, call)) {
|
||||
Expression operand = call.astOperand();
|
||||
if (operand != null) {
|
||||
ResolvedNode resolved = mContext.resolve(operand);
|
||||
UExpression operand = UastUtils.getReceiver(call);
|
||||
if (operand instanceof UResolvable) {
|
||||
UDeclaration resolved = ((UResolvable) operand).resolve(mContext);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
return true;
|
||||
} else if (resolved instanceof ResolvedMethod
|
||||
&& operand instanceof MethodInvocation
|
||||
&& isCommittedInChainedCalls(mContext,(MethodInvocation) operand)) {
|
||||
} else if (resolved instanceof UFunction
|
||||
&& operand instanceof UCallExpression
|
||||
&& isCommittedInChainedCalls(mContext, (UCallExpression) operand)) {
|
||||
// Check that the target of the committed chains is the
|
||||
// right variable!
|
||||
while (operand instanceof MethodInvocation) {
|
||||
operand = ((MethodInvocation)operand).astOperand();
|
||||
while (operand instanceof UCallExpression) {
|
||||
operand = UastUtils.getReceiver((UCallExpression)operand);
|
||||
}
|
||||
if (operand instanceof VariableReference) {
|
||||
resolved = mContext.resolve(operand);
|
||||
if (operand instanceof USimpleReferenceExpression) {
|
||||
resolved = ((USimpleReferenceExpression)operand).resolve(mContext);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
return true;
|
||||
@@ -344,11 +334,10 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
}
|
||||
} else if (isShowFragmentMethodCall(mContext, call)) {
|
||||
StrictListAccessor<Expression, MethodInvocation> arguments =
|
||||
call.astArguments();
|
||||
List<UExpression> arguments = call.getValueArguments();
|
||||
if (arguments.size() == 2) {
|
||||
Expression first = arguments.first();
|
||||
ResolvedNode resolved = mContext.resolve(first);
|
||||
UExpression first = arguments.get(0);
|
||||
UDeclaration resolved = UastUtils.resolveIfCan(first, mContext);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
return true;
|
||||
@@ -359,29 +348,29 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
};
|
||||
|
||||
method.accept(commitVisitor);
|
||||
commitVisitor.handle(method);
|
||||
if (commitVisitor.isCleanedUp() || commitVisitor.variableEscapes()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String message = "This transaction should be completed with a `commit()` call";
|
||||
context.report(COMMIT_FRAGMENT, node, context.getLocation(node.astName()),
|
||||
message);
|
||||
context.report(COMMIT_FRAGMENT, node, UastAndroidUtils.getLocation(node.getFunctionReference()),
|
||||
message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isCommittedInChainedCalls(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation node) {
|
||||
private static boolean isCommittedInChainedCalls(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression node) {
|
||||
// Look for chained calls since the FragmentManager methods all return "this"
|
||||
// to allow constructor chaining, e.g.
|
||||
// getFragmentManager().beginTransaction().addToBackStack("test")
|
||||
// .disallowAddToBackStack().hide(mFragment2).setBreadCrumbShortTitle("test")
|
||||
// .show(mFragment2).setCustomAnimations(0, 0).commit();
|
||||
Node parent = node.getParent();
|
||||
while (parent instanceof MethodInvocation) {
|
||||
MethodInvocation methodInvocation = (MethodInvocation) parent;
|
||||
UElement parent = node.getParent();
|
||||
while (parent instanceof UCallExpression) {
|
||||
UCallExpression methodInvocation = (UCallExpression) parent;
|
||||
if (isTransactionCommitMethodCall(context, methodInvocation)
|
||||
|| isShowFragmentMethodCall(context, methodInvocation)) {
|
||||
return true;
|
||||
@@ -393,74 +382,71 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isTransactionCommitMethodCall(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation call) {
|
||||
private static boolean isTransactionCommitMethodCall(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression call) {
|
||||
|
||||
String methodName = call.astName().astValue();
|
||||
String methodName = call.getFunctionName();
|
||||
return (COMMIT.equals(methodName) || COMMIT_ALLOWING_LOSS.equals(methodName)) &&
|
||||
isMethodOnFragmentClass(context, call,
|
||||
FRAGMENT_TRANSACTION_CLS,
|
||||
FRAGMENT_TRANSACTION_V4_CLS);
|
||||
}
|
||||
|
||||
private static boolean isShowFragmentMethodCall(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation call) {
|
||||
String methodName = call.astName().astValue();
|
||||
private static boolean isShowFragmentMethodCall(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression call) {
|
||||
String methodName = call.getFunctionName();
|
||||
return SHOW.equals(methodName)
|
||||
&& isMethodOnFragmentClass(context, call,
|
||||
DIALOG_FRAGMENT, DIALOG_V4_FRAGMENT);
|
||||
}
|
||||
|
||||
private static boolean isMethodOnFragmentClass(
|
||||
@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation call,
|
||||
@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression call,
|
||||
@NonNull String fragmentClass,
|
||||
@NonNull String v4FragmentClass) {
|
||||
ResolvedNode resolved = context.resolve(call);
|
||||
if (resolved instanceof ResolvedMethod) {
|
||||
ResolvedClass containingClass = ((ResolvedMethod) resolved).getContainingClass();
|
||||
return containingClass.isSubclassOf(fragmentClass, false) ||
|
||||
containingClass.isSubclassOf(v4FragmentClass, false);
|
||||
UFunction resolved = call.resolve(context);
|
||||
if (resolved != null) {
|
||||
UClass containingClass = UastUtils.getContainingClassOrEmpty(resolved);
|
||||
return containingClass.isSubclassOf(fragmentClass) ||
|
||||
containingClass.isSubclassOf(v4FragmentClass);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ResolvedVariable getVariable(@NonNull JavaContext context,
|
||||
@NonNull Node expression) {
|
||||
Node parent = expression.getParent();
|
||||
if (parent instanceof BinaryExpression) {
|
||||
BinaryExpression binaryExpression = (BinaryExpression) parent;
|
||||
if (binaryExpression.astOperator() == BinaryOperator.ASSIGN) {
|
||||
Expression lhs = binaryExpression.astLeft();
|
||||
ResolvedNode resolved = context.resolve(lhs);
|
||||
if (resolved instanceof ResolvedVariable) {
|
||||
return (ResolvedVariable) resolved;
|
||||
public static UVariable getVariable(@NonNull UastAndroidContext context,
|
||||
@NonNull UElement expression) {
|
||||
UElement parent = expression.getParent();
|
||||
if (parent instanceof UBinaryExpression) {
|
||||
UBinaryExpression binaryExpression = (UBinaryExpression) parent;
|
||||
if (binaryExpression.getOperator() == UastBinaryOperator.ASSIGN) {
|
||||
UExpression lhs = binaryExpression.getLeftOperand();
|
||||
if (lhs instanceof UResolvable) {
|
||||
UDeclaration resolved = ((UResolvable) lhs).resolve(context);
|
||||
if (resolved instanceof UVariable) {
|
||||
return (UVariable) resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (parent instanceof VariableDefinitionEntry) {
|
||||
ResolvedNode resolved = context.resolve(parent);
|
||||
if (resolved instanceof ResolvedVariable) {
|
||||
return (ResolvedVariable) resolved;
|
||||
}
|
||||
} else if (parent instanceof UVariable) {
|
||||
return (UVariable) parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isBeginTransaction(@NonNull JavaContext context,
|
||||
@NonNull MethodInvocation node) {
|
||||
String methodName = node.astName().astValue();
|
||||
assert methodName.equals(BEGIN_TRANSACTION) : methodName;
|
||||
private static boolean isBeginTransaction(@NonNull UastAndroidContext context,
|
||||
@NonNull UCallExpression node) {
|
||||
String methodName = node.getFunctionName();
|
||||
assert BEGIN_TRANSACTION.equals(methodName) : methodName;
|
||||
if (BEGIN_TRANSACTION.equals(methodName)) {
|
||||
ResolvedNode resolved = context.resolve(node);
|
||||
if (resolved instanceof ResolvedMethod) {
|
||||
ResolvedMethod method = (ResolvedMethod) resolved;
|
||||
ResolvedClass containingClass = method.getContainingClass();
|
||||
if (containingClass.isSubclassOf(FRAGMENT_MANAGER_CLS, false)
|
||||
|| containingClass.isSubclassOf(FRAGMENT_MANAGER_V4_CLS,
|
||||
false)) {
|
||||
UFunction method = node.resolve(context);
|
||||
if (method != null) {
|
||||
UClass containingClass = UastUtils.getContainingClassOrEmpty(method);
|
||||
if (containingClass.isSubclassOf(FRAGMENT_MANAGER_CLS)
|
||||
|| containingClass.isSubclassOf(FRAGMENT_MANAGER_V4_CLS)) {
|
||||
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 database cursor we're looking for a "close" call, etc.
|
||||
*/
|
||||
private abstract static class FinishVisitor extends ForwardingAstVisitor {
|
||||
protected final JavaContext mContext;
|
||||
protected final List<ResolvedVariable> mVariables;
|
||||
private abstract static class FinishVisitor extends UastVisitor {
|
||||
protected final UastAndroidContext mContext;
|
||||
protected final List<UVariable> mVariables;
|
||||
private boolean mContainsCleanup;
|
||||
private boolean mEscapes;
|
||||
|
||||
public FinishVisitor(JavaContext context, @NonNull ResolvedVariable variable) {
|
||||
public FinishVisitor(UastAndroidContext context, @NonNull UVariable variable) {
|
||||
mContext = context;
|
||||
mVariables = Lists.newArrayList(variable);
|
||||
}
|
||||
@@ -495,25 +481,25 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(Node node) {
|
||||
return mContainsCleanup || super.visitNode(node);
|
||||
public void process(@NotNull UElement element) {
|
||||
if (!mContainsCleanup) {
|
||||
super.process(element);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean isCleanupCall(@NonNull MethodInvocation call);
|
||||
protected abstract boolean isCleanupCall(@NonNull UCallExpression call);
|
||||
|
||||
@Override
|
||||
public boolean visitMethodInvocation(MethodInvocation call) {
|
||||
public boolean visitCallExpression(@NotNull UCallExpression call) {
|
||||
if (mContainsCleanup) {
|
||||
return true;
|
||||
}
|
||||
|
||||
super.visitMethodInvocation(call);
|
||||
|
||||
// Look for escapes
|
||||
if (!mEscapes) {
|
||||
for (Expression expression : call.astArguments()) {
|
||||
if (expression instanceof VariableReference) {
|
||||
ResolvedNode resolved = mContext.resolve(expression);
|
||||
for (UExpression expression : call.getValueArguments()) {
|
||||
if (expression instanceof USimpleReferenceExpression) {
|
||||
UDeclaration resolved = ((USimpleReferenceExpression) expression).resolve(mContext);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
mEscapes = true;
|
||||
@@ -521,12 +507,11 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
// Special case: MotionEvent.obtain(MotionEvent): passing in an
|
||||
// event here does not recycle the event, and we also know it
|
||||
// doesn't escape
|
||||
if (OBTAIN.equals(call.astName().astValue())) {
|
||||
ResolvedNode r = mContext.resolve(call);
|
||||
if (r instanceof ResolvedMethod) {
|
||||
ResolvedMethod method = (ResolvedMethod) r;
|
||||
ResolvedClass cls = method.getContainingClass();
|
||||
if (cls.matches(MOTION_EVENT_CLS)) {
|
||||
if (OBTAIN.equals(call.getFunctionName())) {
|
||||
UFunction method = call.resolve(mContext);
|
||||
if (method != null) {
|
||||
UClass cls = UastUtils.getContainingClassOrEmpty(method);
|
||||
if (cls.matchesFqName(MOTION_EVENT_CLS)) {
|
||||
mEscapes = false;
|
||||
}
|
||||
}
|
||||
@@ -545,57 +530,61 @@ public class CleanupDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) {
|
||||
Expression initializer = node.astInitializer();
|
||||
if (initializer instanceof VariableReference) {
|
||||
ResolvedNode resolved = mContext.resolve(initializer);
|
||||
public boolean visitVariable(@NotNull UVariable node) {
|
||||
UExpression initializer = node.getInitializer();
|
||||
if (initializer instanceof USimpleReferenceExpression) {
|
||||
UDeclaration resolved = ((USimpleReferenceExpression) initializer).resolve(mContext);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
ResolvedNode resolvedVariable = mContext.resolve(node);
|
||||
if (resolvedVariable instanceof ResolvedVariable) {
|
||||
ResolvedVariable variable = (ResolvedVariable) resolvedVariable;
|
||||
mVariables.add(variable);
|
||||
} else if (resolvedVariable instanceof ResolvedField) {
|
||||
if (node.getKind() == UastVariableKind.LOCAL_VARIABLE) {
|
||||
mVariables.add(node);
|
||||
} else if (node.getKind() == UastVariableKind.MEMBER) {
|
||||
mEscapes = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitVariableDefinitionEntry(node);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitBinaryExpression(BinaryExpression node) {
|
||||
if (node.astOperator() == BinaryOperator.ASSIGN) {
|
||||
Expression rhs = node.astRight();
|
||||
if (rhs instanceof VariableReference) {
|
||||
ResolvedNode resolved = mContext.resolve(rhs);
|
||||
public boolean visitBinaryExpression(@NotNull UBinaryExpression node) {
|
||||
if (node.getOperator() == UastBinaryOperator.ASSIGN) {
|
||||
UExpression rhs = node.getRightOperand();
|
||||
if (rhs instanceof USimpleReferenceExpression) {
|
||||
UDeclaration resolved = ((USimpleReferenceExpression) rhs).resolve(mContext);
|
||||
UExpression leftOperand = node.getLeftOperand();
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
ResolvedNode resolvedLhs = mContext.resolve(node.astLeft());
|
||||
if (resolvedLhs instanceof ResolvedVariable) {
|
||||
ResolvedVariable variable = (ResolvedVariable) resolvedLhs;
|
||||
mVariables.add(variable);
|
||||
} else if (resolvedLhs instanceof ResolvedField) {
|
||||
mEscapes = true;
|
||||
if (resolved != null && mVariables.contains(resolved) && leftOperand instanceof UResolvable) {
|
||||
UDeclaration resolvedLhs = ((UResolvable) leftOperand).resolve(mContext);
|
||||
if (resolvedLhs instanceof UVariable) {
|
||||
UVariable variable = (UVariable) resolvedLhs;
|
||||
if (variable.getKind() == UastVariableKind.LOCAL_VARIABLE) {
|
||||
mVariables.add(variable);
|
||||
} else if (variable.getKind() == UastVariableKind.MEMBER) {
|
||||
mEscapes = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitBinaryExpression(node);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitReturn(Return node) {
|
||||
Expression value = node.astValue();
|
||||
if (value instanceof VariableReference) {
|
||||
ResolvedNode resolved = mContext.resolve(value);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
mEscapes = true;
|
||||
public boolean visitSpecialExpressionList(@NotNull USpecialExpressionList node) {
|
||||
if (node.getKind() == UastSpecialExpressionKind.RETURN) {
|
||||
UExpression value = node.firstOrNull();
|
||||
if (value instanceof USimpleReferenceExpression) {
|
||||
UDeclaration resolved = ((USimpleReferenceExpression) value).resolve(mContext);
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (resolved != null && mVariables.contains(resolved)) {
|
||||
mEscapes = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitReturn(node);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -14,20 +14,20 @@
|
||||
* 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 com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.ClassContext;
|
||||
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.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.ClassContext;
|
||||
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.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
||||
@@ -14,33 +14,26 @@
|
||||
* 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.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.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 com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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 java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.Comment;
|
||||
import lombok.ast.ForwardingAstVisitor;
|
||||
import lombok.ast.Node;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
|
||||
/**
|
||||
* 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 Implementation IMPLEMENTATION = new Implementation(
|
||||
@@ -96,7 +89,7 @@ public class CommentDetector extends Detector implements Detector.JavaScanner {
|
||||
return Speed.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
/*@Override
|
||||
public List<Class<? extends Node>> getApplicableNodeTypes() {
|
||||
if (USE_AST) {
|
||||
return Collections.<Class<? extends Node>>singletonList(Comment.class);
|
||||
@@ -135,7 +128,7 @@ public class CommentDetector extends Detector implements Detector.JavaScanner {
|
||||
} else if (next == '*') {
|
||||
// Block comment
|
||||
int start = i + 2;
|
||||
int end = source.indexOf("*/", start);
|
||||
int end = source.indexOf("*//*", start);
|
||||
if (end == -1) {
|
||||
end = n;
|
||||
}
|
||||
@@ -195,5 +188,5 @@ public class CommentDetector extends Detector implements Detector.JavaScanner {
|
||||
"to release");
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.Nullable;
|
||||
|
||||
+49
-59
@@ -14,7 +14,7 @@
|
||||
* 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_VIEWGROUP;
|
||||
@@ -22,36 +22,29 @@ import static com.android.SdkConstants.DOT_LAYOUT_PARAMS;
|
||||
import static com.android.SdkConstants.R_STYLEABLE_PREFIX;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.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 com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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 java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.ClassDeclaration;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.ExpressionStatement;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import lombok.ast.StrictListAccessor;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
|
||||
/**
|
||||
* Makes sure that custom views use a declare styleable that matches
|
||||
* 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(
|
||||
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$
|
||||
|
||||
/** Constructs a new {@link com.android.tools.lint.checks.CustomViewDetector} check */
|
||||
/** Constructs a new {@link CustomViewDetector} check */
|
||||
public CustomViewDetector() {
|
||||
}
|
||||
|
||||
@@ -91,79 +84,76 @@ public class CustomViewDetector extends Detector implements Detector.JavaScanner
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Collections.singletonList(OBTAIN_STYLED_ATTRIBUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation node) {
|
||||
if (node.getParent() instanceof ExpressionStatement) {
|
||||
if (!context.isContextMethod(node)) {
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
if (node.getParent() instanceof UExpression) {
|
||||
if (!context.getLintContext().isContextMethod(node)) {
|
||||
return;
|
||||
}
|
||||
StrictListAccessor<Expression, MethodInvocation> expressions = node.astArguments();
|
||||
List<UExpression> expressions = node.getValueArguments();
|
||||
int size = expressions.size();
|
||||
// Which parameter contains the styleable (attrs) ?
|
||||
int parameterIndex;
|
||||
if (size == 1) {
|
||||
// obtainStyledAttributes(int[] attrs)
|
||||
parameterIndex = 0;
|
||||
} else {
|
||||
} else if (size > 1) {
|
||||
// obtainStyledAttributes(int resid, int[] attrs)
|
||||
// obtainStyledAttributes(AttributeSet set, int[] attrs)
|
||||
// obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
|
||||
parameterIndex = 1;
|
||||
}
|
||||
Expression expression = Iterators.get(node.astArguments().iterator(), parameterIndex,
|
||||
null);
|
||||
if (expression == null) {
|
||||
} else {
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
ResolvedNode resolved = context.resolve(cls);
|
||||
if (!(resolved instanceof ResolvedClass)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String className = cls.astName().astValue();
|
||||
ResolvedClass resolvedClass = (ResolvedClass) resolved;
|
||||
if (resolvedClass.isSubclassOf(CLASS_VIEW, false)) {
|
||||
String className = resolvedClass.getName();
|
||||
if (resolvedClass.isSubclassOf(CLASS_VIEW)) {
|
||||
if (!styleableName.equals(className)) {
|
||||
String message = String.format(
|
||||
"By convention, the custom view (`%1$s`) and the declare-styleable (`%2$s`) "
|
||||
+ "should have the same name (various editor features rely on "
|
||||
+ "this convention)",
|
||||
className, styleableName);
|
||||
context.report(ISSUE, node, context.getLocation(expression), message);
|
||||
"By convention, the custom view (`%1$s`) and the declare-styleable (`%2$s`) "
|
||||
+ "should have the same name (various editor features rely on "
|
||||
+ "this convention)",
|
||||
className, styleableName);
|
||||
context.report(ISSUE, node, UastAndroidUtils.getLocation(expression), message);
|
||||
}
|
||||
} else if (resolvedClass.isSubclassOf(CLASS_VIEWGROUP + DOT_LAYOUT_PARAMS, false)) {
|
||||
ClassDeclaration outer = JavaContext.findSurroundingClass(cls.getParent());
|
||||
} else if (resolvedClass.isSubclassOf(CLASS_VIEWGROUP + DOT_LAYOUT_PARAMS)) {
|
||||
UClass outer = UastUtils.getContainingClass(resolvedClass);
|
||||
if (outer == null) {
|
||||
return;
|
||||
}
|
||||
String layoutClassName = outer.astName().astValue();
|
||||
String layoutClassName = outer.getName();
|
||||
String expectedName = layoutClassName + "_Layout";
|
||||
if (!styleableName.equals(expectedName)) {
|
||||
String message = String.format(
|
||||
"By convention, the declare-styleable (`%1$s`) for a layout parameter "
|
||||
+ "class (`%2$s`) is expected to be the surrounding "
|
||||
+ "class (`%3$s`) plus \"`_Layout`\", e.g. `%4$s`. "
|
||||
+ "(Various editor features rely on this convention.)",
|
||||
styleableName, className, layoutClassName, expectedName);
|
||||
context.report(ISSUE, node, context.getLocation(expression), message);
|
||||
"By convention, the declare-styleable (`%1$s`) for a layout parameter "
|
||||
+ "class (`%2$s`) is expected to be the surrounding "
|
||||
+ "class (`%3$s`) plus \"`_Layout`\", e.g. `%4$s`. "
|
||||
+ "(Various editor features rely on this convention.)",
|
||||
styleableName, className, layoutClassName, expectedName);
|
||||
context.report(ISSUE, node, UastAndroidUtils.getLocation(expression), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,21 +14,20 @@
|
||||
* 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 com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.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.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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.Location;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.io.File;
|
||||
@@ -36,24 +35,17 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.ast.ArrayAccess;
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.BinaryExpression;
|
||||
import lombok.ast.Cast;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.ForwardingAstVisitor;
|
||||
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;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
import org.jetbrains.uast.visitor.UastVisitor;
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
"CutPasteId", //$NON-NLS-1$
|
||||
@@ -73,8 +65,8 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
||||
CutPasteDetector.class,
|
||||
Scope.JAVA_FILE_SCOPE));
|
||||
|
||||
private Node mLastMethod;
|
||||
private Map<String, MethodInvocation> mIds;
|
||||
private UFunction mLastMethod;
|
||||
private Map<String, UCallExpression> mIds;
|
||||
private Map<String, String> mLhs;
|
||||
private Map<String, String> mCallOperands;
|
||||
|
||||
@@ -87,22 +79,22 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Collections.singletonList("findViewById"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation call) {
|
||||
String lhs = getLhs(call);
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
String lhs = getLhs(node);
|
||||
if (lhs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node method = JavaContext.findSurroundingMethod(call);
|
||||
UFunction method = UastUtils.getContainingFunction(node);
|
||||
if (method == null) {
|
||||
return;
|
||||
} else if (method != mLastMethod) {
|
||||
@@ -112,16 +104,20 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
||||
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();
|
||||
if (first instanceof Select) {
|
||||
Select select = (Select) first;
|
||||
String id = select.astIdentifier().astValue();
|
||||
Expression operand = select.astOperand();
|
||||
if (operand instanceof Select) {
|
||||
Select type = (Select) operand;
|
||||
if (type.astIdentifier().astValue().equals(RESOURCE_CLZ_ID)) {
|
||||
UExpression first = node.getValueArguments().get(0);
|
||||
if (first instanceof UQualifiedExpression) {
|
||||
UQualifiedExpression select = (UQualifiedExpression) first;
|
||||
String id = select.getSelector().renderString();
|
||||
UExpression operand = select.getReceiver();
|
||||
if (operand instanceof UQualifiedExpression) {
|
||||
UQualifiedExpression type = (UQualifiedExpression) operand;
|
||||
if (type.getSelector().renderString().equals(RESOURCE_CLZ_ID)) {
|
||||
if (mIds.containsKey(id)) {
|
||||
if (lhs.equals(mLhs.get(id))) {
|
||||
return;
|
||||
@@ -129,45 +125,49 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
||||
if (!callOperand.equals(mCallOperands.get(id))) {
|
||||
return;
|
||||
}
|
||||
MethodInvocation earlierCall = mIds.get(id);
|
||||
if (!isReachableFrom(method, earlierCall, call)) {
|
||||
UCallExpression earlierCall = mIds.get(id);
|
||||
if (!isReachableFrom(method, earlierCall, node)) {
|
||||
return;
|
||||
}
|
||||
Location location = context.getLocation(call);
|
||||
Location secondary = context.getLocation(earlierCall);
|
||||
secondary.setMessage("First usage here");
|
||||
location.setSecondary(secondary);
|
||||
context.report(ISSUE, call, location, String.format(
|
||||
"The id `%1$s` has already been looked up in this method; possible " +
|
||||
"cut & paste error?", first.toString()));
|
||||
Location location = UastAndroidUtils.getLocation(node);
|
||||
Location secondary = UastAndroidUtils.getLocation(earlierCall);
|
||||
if (location != null && secondary != null) {
|
||||
secondary.setMessage("First usage here");
|
||||
location.setSecondary(secondary);
|
||||
context.report(ISSUE, node, location, String.format(
|
||||
"The id `%1$s` has already been looked up in this method; possible " +
|
||||
"cut & paste error?", first.toString()));
|
||||
}
|
||||
} else {
|
||||
mIds.put(id, call);
|
||||
mIds.put(id, node);
|
||||
mLhs.put(id, lhs);
|
||||
mCallOperands.put(id, callOperand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getLhs(@NonNull MethodInvocation call) {
|
||||
Node parent = call.getParent();
|
||||
if (parent instanceof Cast) {
|
||||
private static String getLhs(@NonNull UCallExpression call) {
|
||||
UElement parent = call.getParent();
|
||||
if (UastBinaryExpressionWithTypeUtils.isTypeCast(parent)) {
|
||||
assert parent != null;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
if (parent instanceof VariableDefinitionEntry) {
|
||||
VariableDefinitionEntry vde = (VariableDefinitionEntry) parent;
|
||||
return vde.astName().astValue();
|
||||
} else if (parent instanceof BinaryExpression) {
|
||||
BinaryExpression be = (BinaryExpression) parent;
|
||||
Expression left = be.astLeft();
|
||||
if (left instanceof VariableReference || left instanceof Select) {
|
||||
return be.astLeft().toString();
|
||||
} else if (left instanceof ArrayAccess) {
|
||||
ArrayAccess aa = (ArrayAccess) left;
|
||||
return aa.astOperand().toString();
|
||||
if (parent instanceof UVariable) {
|
||||
UVariable vde = (UVariable) parent;
|
||||
return vde.getName();
|
||||
} else if (parent instanceof UBinaryExpression) {
|
||||
UBinaryExpression be = (UBinaryExpression) parent;
|
||||
UExpression left = be.getLeftOperand();
|
||||
if (left instanceof USimpleReferenceExpression || left instanceof UQualifiedExpression) {
|
||||
return be.getLeftOperand().toString();
|
||||
} else if (left instanceof UArrayAccessExpression) {
|
||||
UArrayAccessExpression aa = (UArrayAccessExpression) left;
|
||||
return aa.getReceiver().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,22 +175,21 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
||||
}
|
||||
|
||||
private static boolean isReachableFrom(
|
||||
@NonNull Node method,
|
||||
@NonNull MethodInvocation from,
|
||||
@NonNull MethodInvocation to) {
|
||||
@NonNull UElement method,
|
||||
@NonNull UCallExpression from,
|
||||
@NonNull UCallExpression to) {
|
||||
ReachableVisitor visitor = new ReachableVisitor(from, to);
|
||||
method.accept(visitor);
|
||||
|
||||
visitor.process(method);
|
||||
return visitor.isReachable();
|
||||
}
|
||||
|
||||
private static class ReachableVisitor extends ForwardingAstVisitor {
|
||||
@NonNull private final MethodInvocation mFrom;
|
||||
@NonNull private final MethodInvocation mTo;
|
||||
private static class ReachableVisitor extends UastVisitor {
|
||||
@NonNull private final UCallExpression mFrom;
|
||||
@NonNull private final UCallExpression mTo;
|
||||
private boolean mReachable;
|
||||
private boolean mSeenEnd;
|
||||
|
||||
public ReachableVisitor(@NonNull MethodInvocation from, @NonNull MethodInvocation to) {
|
||||
public ReachableVisitor(@NonNull UCallExpression from, @NonNull UCallExpression to) {
|
||||
mFrom = from;
|
||||
mTo = to;
|
||||
}
|
||||
@@ -200,43 +199,42 @@ public class CutPasteDetector extends Detector implements Detector.JavaScanner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitMethodInvocation(MethodInvocation node) {
|
||||
public boolean visitCallExpression(@NotNull UCallExpression node) {
|
||||
if (node == mFrom) {
|
||||
mReachable = true;
|
||||
} else if (node == mTo) {
|
||||
mSeenEnd = true;
|
||||
|
||||
}
|
||||
return super.visitMethodInvocation(node);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitIf(If node) {
|
||||
Expression condition = node.astCondition();
|
||||
Statement body = node.astStatement();
|
||||
Statement elseBody = node.astElseStatement();
|
||||
if (condition != null) {
|
||||
condition.accept(this);
|
||||
}
|
||||
public boolean visitIfExpression(@NotNull UIfExpression node) {
|
||||
UExpression condition = node.getCondition();
|
||||
UExpression body = node.getThenBranch();
|
||||
UElement elseBody = node.getElseBranch();
|
||||
process(condition);
|
||||
|
||||
if (body != null) {
|
||||
boolean wasReachable = mReachable;
|
||||
body.accept(this);
|
||||
process(body);
|
||||
mReachable = wasReachable;
|
||||
}
|
||||
if (elseBody != null) {
|
||||
boolean wasReachable = mReachable;
|
||||
elseBody.accept(this);
|
||||
process(elseBody);
|
||||
mReachable = wasReachable;
|
||||
}
|
||||
|
||||
endVisit(node);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(Node node) {
|
||||
return mSeenEnd;
|
||||
public void process(@NotNull UElement element) {
|
||||
if (!mSeenEnd) {
|
||||
super.process(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-28
@@ -14,33 +14,33 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
||||
import com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
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.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
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.Location;
|
||||
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 java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.ConstructorInvocation;
|
||||
import org.jetbrains.uast.UFunction;
|
||||
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
|
||||
*/
|
||||
public class DateFormatDetector extends Detector implements JavaScanner {
|
||||
public class DateFormatDetector extends Detector implements UastScanner {
|
||||
|
||||
private static final Implementation IMPLEMENTATION = new Implementation(
|
||||
DateFormatDetector.class,
|
||||
@@ -82,7 +82,7 @@ public class DateFormatDetector extends Detector implements JavaScanner {
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -91,22 +91,21 @@ public class DateFormatDetector extends Detector implements JavaScanner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConstructor(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull ConstructorInvocation node, @NonNull ResolvedMethod constructor) {
|
||||
public void visitConstructor(UastAndroidContext context, UCallExpression functionCall, UFunction constructor) {
|
||||
if (!specifiesLocale(constructor)) {
|
||||
Location location = context.getLocation(node);
|
||||
Location location = UastAndroidUtils.getLocation(functionCall);
|
||||
String message =
|
||||
"To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, " +
|
||||
"or `getTimeInstance()`, or use `new SimpleDateFormat(String template, " +
|
||||
"Locale locale)` with for example `Locale.US` for ASCII dates.";
|
||||
context.report(DATE_FORMAT, node, location, message);
|
||||
"To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, " +
|
||||
"or `getTimeInstance()`, or use `new SimpleDateFormat(String template, " +
|
||||
"Locale locale)` with for example `Locale.US` for ASCII dates.";
|
||||
context.report(DATE_FORMAT, functionCall, location, message);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean specifiesLocale(@NonNull ResolvedMethod method) {
|
||||
for (int i = 0, n = method.getArgumentCount(); i < n; i++) {
|
||||
TypeDescriptor argumentType = method.getArgumentType(i);
|
||||
if (argumentType.matchesSignature(LOCALE_CLS)) {
|
||||
private static boolean specifiesLocale(@NonNull UFunction method) {
|
||||
for (int i = 0, n = method.getValueParameterCount(); i < n; i++) {
|
||||
UType parameterType = method.getValueParameters().get(i).getType();
|
||||
if (parameterType.matchesFqName(LOCALE_CLS)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -14,7 +14,7 @@
|
||||
* 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.ANDROID_URI;
|
||||
@@ -31,14 +31,14 @@ import static com.android.SdkConstants.EDIT_TEXT;
|
||||
import static com.android.SdkConstants.VALUE_TRUE;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
+9
-9
@@ -14,7 +14,7 @@
|
||||
* 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_SUPPORT_PKG_PREFIX;
|
||||
@@ -39,14 +39,14 @@ import static com.android.resources.ResourceFolderType.MENU;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
+10
-10
@@ -14,18 +14,18 @@
|
||||
* 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.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.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 com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
|
||||
+12
-12
@@ -14,7 +14,7 @@
|
||||
* 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.ATTR_ID;
|
||||
@@ -27,17 +27,17 @@ import static com.android.ide.common.resources.configuration.FolderConfiguration
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
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 com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
|
||||
+14
-14
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
|
||||
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.resources.ResourceFolderType;
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Location.Handle;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.TextFormat;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Location.Handle;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.detector.api.TextFormat;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.android.utils.Pair;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
+12
-12
@@ -14,21 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.tools.lint.checks;
|
||||
package com.android.tools.klint.checks;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.DefaultPosition;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Position;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.DefaultPosition;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Position;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
+12
-12
@@ -14,20 +14,20 @@
|
||||
* 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.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.ClassContext;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
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 com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.ClassContext;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
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 com.google.common.collect.Maps;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
@@ -14,34 +14,28 @@
|
||||
* 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_V4_FRAGMENT;
|
||||
import static com.android.tools.lint.client.api.JavaParser.ResolvedClass;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.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.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
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.Location;
|
||||
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 java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.ClassDeclaration;
|
||||
import lombok.ast.ConstructorDeclaration;
|
||||
import lombok.ast.Node;
|
||||
import lombok.ast.NormalTypeBody;
|
||||
import lombok.ast.TypeMember;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* (and countless duplicates)
|
||||
*/
|
||||
public class FragmentDetector extends Detector implements JavaScanner {
|
||||
public class FragmentDetector extends Detector implements UastScanner {
|
||||
/** Are fragment subclasses instantiatable? */
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
"ValidFragment", //$NON-NLS-1$
|
||||
@@ -86,80 +80,67 @@ public class FragmentDetector extends Detector implements JavaScanner {
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> applicableSuperClasses() {
|
||||
public List<String> getApplicableSuperClasses() {
|
||||
return Arrays.asList(CLASS_FRAGMENT, CLASS_V4_FRAGMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClass(@NonNull JavaContext context, @Nullable ClassDeclaration node,
|
||||
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
|
||||
if (node == null) {
|
||||
public void visitClass(UastAndroidContext context, UClass cls) {
|
||||
if (cls.hasModifier(UastModifier.ABSTRACT) || cls.isInterface()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = node.astModifiers().getEffectiveModifierFlags();
|
||||
if ((flags & Modifier.ABSTRACT) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((flags & Modifier.PUBLIC) == 0) {
|
||||
if (!cls.getVisibility().isPublic()) {
|
||||
String message = String.format("This fragment class should be public (%1$s)",
|
||||
cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
cls.getFqName());
|
||||
context.report(ISSUE, cls, UastAndroidUtils.getLocation(cls.getNameElement()), message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
|
||||
if (UastUtils.getContainingClass(cls) != null && cls.hasModifier(UastModifier.INNER)) {
|
||||
String message = String.format(
|
||||
"This fragment inner class should be static (%1$s)", cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
"This fragment inner class should be static (%1$s)", cls.getName());
|
||||
context.report(ISSUE, cls, UastAndroidUtils.getLocation(cls.getNameElement()), message);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasDefaultConstructor = false;
|
||||
boolean hasConstructor = false;
|
||||
NormalTypeBody body = node.astBody();
|
||||
if (body != null) {
|
||||
for (TypeMember member : body.astMembers()) {
|
||||
if (member instanceof ConstructorDeclaration) {
|
||||
hasConstructor = true;
|
||||
ConstructorDeclaration constructor = (ConstructorDeclaration) member;
|
||||
if (constructor.astParameters().isEmpty()) {
|
||||
// The constructor must be public
|
||||
if (constructor.astModifiers().isPublic()) {
|
||||
hasDefaultConstructor = true;
|
||||
} else {
|
||||
Location location = context.getLocation(
|
||||
constructor.astTypeName());
|
||||
context.report(ISSUE, constructor, location,
|
||||
"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);
|
||||
}
|
||||
|
||||
for (UFunction constructor : cls.getConstructors()) {
|
||||
hasConstructor = true;
|
||||
if (constructor.getValueParameterCount() == 0) {
|
||||
if (constructor.getVisibility().isPublic()) {
|
||||
hasDefaultConstructor = true;
|
||||
} else {
|
||||
Location location = UastAndroidUtils.getLocation(constructor.getNameElement());
|
||||
context.report(ISSUE, constructor, location,
|
||||
"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 = 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) {
|
||||
String message = String.format(
|
||||
"This fragment should provide a default constructor (a public " +
|
||||
"constructor with no arguments) (`%1$s`)",
|
||||
cls.getName());
|
||||
context.report(ISSUE, node, context.getLocation(node.astName()), message);
|
||||
"This fragment should provide a default constructor (a public " +
|
||||
"constructor with no arguments) (`%1$s`)",
|
||||
cls.getName());
|
||||
context.report(ISSUE, cls, UastAndroidUtils.getLocation(cls.getNameElement()), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -14,25 +14,25 @@
|
||||
* 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.Nullable;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
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.Location;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
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
|
||||
*/
|
||||
public class FullBackupContentDetector extends ResourceXmlDetector implements JavaScanner {
|
||||
public class FullBackupContentDetector extends ResourceXmlDetector implements UastScanner {
|
||||
/**
|
||||
* Validation of {@code <full-backup-content>} XML elements
|
||||
*/
|
||||
|
||||
+51
-71
@@ -14,36 +14,25 @@
|
||||
* 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.Nullable;
|
||||
import com.android.tools.lint.client.api.JavaParser;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedField;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
|
||||
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
|
||||
import com.android.tools.lint.client.api.JavaParser.TypeDescriptor;
|
||||
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.klint.client.api.JavaParser;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
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 java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.AstVisitor;
|
||||
import lombok.ast.BinaryExpression;
|
||||
import lombok.ast.BinaryOperator;
|
||||
import lombok.ast.Expression;
|
||||
import lombok.ast.IntegralLiteral;
|
||||
import lombok.ast.MethodInvocation;
|
||||
import lombok.ast.StrictListAccessor;
|
||||
import lombok.ast.StringLiteral;
|
||||
import org.jetbrains.uast.*;
|
||||
import org.jetbrains.uast.check.UastAndroidContext;
|
||||
import org.jetbrains.uast.check.UastAndroidUtils;
|
||||
import org.jetbrains.uast.check.UastScanner;
|
||||
|
||||
public class GetSignaturesDetector extends Detector implements Detector.JavaScanner {
|
||||
public class GetSignaturesDetector extends Detector implements UastScanner {
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
"PackageManagerGetSignatures", //$NON-NLS-1$
|
||||
"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 int GET_SIGNATURES_FLAG = 0x00000040; //$NON-NLS-1$
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<String> getApplicableMethodNames() {
|
||||
public List<String> getApplicableFunctionNames() {
|
||||
return Collections.singletonList(GET_PACKAGE_INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
|
||||
@NonNull MethodInvocation node) {
|
||||
ResolvedNode resolved = context.resolve(node);
|
||||
public void visitFunctionCall(UastAndroidContext context, UCallExpression node) {
|
||||
UFunction resolved = node.resolve(context);
|
||||
|
||||
if (!(resolved instanceof ResolvedMethod) ||
|
||||
!((ResolvedMethod) resolved).getContainingClass()
|
||||
.isSubclassOf(PACKAGE_MANAGER_CLASS, false)) {
|
||||
if (resolved == null ||
|
||||
!UastUtils.getContainingClassOrEmpty(resolved).isSubclassOf(PACKAGE_MANAGER_CLASS)) {
|
||||
return;
|
||||
}
|
||||
StrictListAccessor<Expression, MethodInvocation> argumentList = node.astArguments();
|
||||
|
||||
List<UExpression> argumentList = node.getValueArguments();
|
||||
|
||||
// Ignore if the method doesn't fit our description.
|
||||
if (argumentList != null && argumentList.size() == 2) {
|
||||
TypeDescriptor firstParameterType = context.getType(argumentList.first());
|
||||
if (argumentList.size() == 2) {
|
||||
UType firstParameterType = argumentList.get(0).getExpressionType();
|
||||
if (firstParameterType != null
|
||||
&& firstParameterType.matchesSignature(JavaParser.TYPE_STRING)) {
|
||||
maybeReportIssue(calculateValue(context, argumentList.last()), context, node);
|
||||
&& firstParameterType.matchesFqName(JavaParser.TYPE_STRING)) {
|
||||
maybeReportIssue(calculateValue(context, argumentList.get(1)), context, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void maybeReportIssue(
|
||||
int flagValue, JavaContext context, MethodInvocation node) {
|
||||
int flagValue, UastAndroidContext context, UCallExpression node) {
|
||||
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 "
|
||||
+ "could be exploited if not validated properly; "
|
||||
+ "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
|
||||
// flags that combined via bitwise operands.
|
||||
if (expression instanceof IntegralLiteral) {
|
||||
return ((IntegralLiteral) expression).astIntValue();
|
||||
if (UastLiteralUtils.isIntegralLiteral(expression)) {
|
||||
return (int) UastLiteralUtils.getLongValue((ULiteralExpression) expression);
|
||||
}
|
||||
|
||||
ResolvedNode resolvedNode = context.resolve(expression);
|
||||
if (resolvedNode instanceof ResolvedField) {
|
||||
Object value = ((ResolvedField) resolvedNode).getValue();
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
if (expression instanceof UResolvable) {
|
||||
UDeclaration resolvedNode = ((UResolvable) expression).resolve(context);
|
||||
if (resolvedNode instanceof UVariable) {
|
||||
UExpression initializer = ((UVariable)resolvedNode).getInitializer();
|
||||
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;
|
||||
}
|
||||
if (operator == BinaryOperator.BITWISE_AND) {
|
||||
if (operator == UastBinaryOperator.BITWISE_AND) {
|
||||
return leftValue & rightValue;
|
||||
}
|
||||
if (operator == BinaryOperator.BITWISE_XOR) {
|
||||
if (operator == UastBinaryOperator.BITWISE_XOR) {
|
||||
return leftValue ^ rightValue;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* 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.GRADLE_PLUGIN_MINIMUM_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.tools.lint.checks.ManifestDetector.TARGET_NEWER;
|
||||
import static com.android.tools.lint.detector.api.LintUtils.findSubstring;
|
||||
import static com.android.tools.klint.detector.api.LintUtils.findSubstring;
|
||||
import static com.google.common.base.Charsets.UTF_8;
|
||||
|
||||
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.SdkMavenRepository;
|
||||
import com.android.sdklib.repository.PreciseRevision;
|
||||
import com.android.tools.lint.client.api.LintClient;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
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 com.android.tools.lint.detector.api.TextFormat;
|
||||
import com.android.tools.klint.client.api.LintClient;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
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 com.android.tools.klint.detector.api.TextFormat;
|
||||
import com.google.common.base.Splitter;
|
||||
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 " +
|
||||
"modes apply. Consider testing and updating this version. " +
|
||||
"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) {
|
||||
mTargetSdkVersion = version;
|
||||
|
||||
+11
-11
@@ -14,7 +14,7 @@
|
||||
* 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_URI;
|
||||
@@ -34,16 +34,16 @@ import static com.android.SdkConstants.XMLNS_PREFIX;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
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 com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
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 com.android.tools.klint.detector.api.TextFormat;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
@@ -14,35 +14,31 @@
|
||||
* 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.Nullable;
|
||||
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.JavaParser.TypeDescriptor;
|
||||
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.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 com.android.tools.klint.detector.api.Category;
|
||||
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.Location;
|
||||
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 java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.ast.ClassDeclaration;
|
||||
import lombok.ast.Node;
|
||||
import org.jetbrains.uast.*;
|
||||
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.
|
||||
* 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 */
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
@@ -78,58 +74,39 @@ public class HandlerDetector extends Detector implements Detector.JavaScanner {
|
||||
return Speed.FAST;
|
||||
}
|
||||
|
||||
// ---- Implements JavaScanner ----
|
||||
// ---- Implements UastScanner ----
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> applicableSuperClasses() {
|
||||
public List<String> getApplicableSuperClasses() {
|
||||
return Collections.singletonList(HANDLER_CLS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClass(@NonNull JavaContext context, @Nullable ClassDeclaration declaration,
|
||||
@NonNull Node node, @NonNull ResolvedClass cls) {
|
||||
if (!isInnerClass(declaration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isStaticClass(declaration)) {
|
||||
public void visitClass(UastAndroidContext context, UClass node) {
|
||||
boolean x = node.hasModifier(UastModifier.INNER);
|
||||
if (!node.hasModifier(UastModifier.INNER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only flag handlers using the default looper
|
||||
if (hasLooperConstructorParameter(cls)) {
|
||||
if (hasLooperConstructorParameter(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node locationNode = node instanceof ClassDeclaration
|
||||
? ((ClassDeclaration) node).astName() : node;
|
||||
Location location = context.getLocation(locationNode);
|
||||
context.report(ISSUE, location, String.format(
|
||||
"This Handler class should be static or leaks might occur (%1$s)",
|
||||
cls.getName()));
|
||||
UElement locationNode = node.getNameElement();
|
||||
Location location = UastAndroidUtils.getLocation(locationNode);
|
||||
context.report(ISSUE, node, location, String.format(
|
||||
"This Handler class should be static or leaks might occur (%1$s)",
|
||||
node.getName()));
|
||||
|
||||
}
|
||||
|
||||
private static boolean isInnerClass(@Nullable ClassDeclaration node) {
|
||||
return node == null || // null class declarations means anonymous inner class
|
||||
JavaContext.getParentOfType(node, ClassDeclaration.class, true) != null;
|
||||
}
|
||||
|
||||
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)) {
|
||||
private static boolean hasLooperConstructorParameter(@NonNull UClass cls) {
|
||||
for (UFunction constructor : cls.getConstructors()) {
|
||||
for (int i = 0, n = constructor.getValueParameterCount(); i < n; i++) {
|
||||
UType type = constructor.getValueParameters().get(i).getType();
|
||||
if (type.matchesFqName(LOOPER_CLS)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -14,22 +14,22 @@
|
||||
* 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_URI;
|
||||
import static com.android.SdkConstants.ATTR_DEBUGGABLE;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
|
||||
|
||||
+9
-9
@@ -14,7 +14,7 @@
|
||||
* 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.ATTR_CONTENT_DESCRIPTION;
|
||||
@@ -26,14 +26,14 @@ import static com.android.SdkConstants.ATTR_TITLE;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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_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_RECEIVER;
|
||||
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.Nullable;
|
||||
@@ -51,26 +51,29 @@ import com.android.builder.model.ProductFlavor;
|
||||
import com.android.builder.model.ProductFlavorContainer;
|
||||
import com.android.resources.Density;
|
||||
import com.android.resources.ResourceFolderType;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Context;
|
||||
import com.android.tools.lint.detector.api.Detector;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.JavaContext;
|
||||
import com.android.tools.lint.detector.api.LintUtils;
|
||||
import com.android.tools.lint.detector.api.Location;
|
||||
import com.android.tools.lint.detector.api.Project;
|
||||
import com.android.tools.lint.detector.api.ResourceXmlDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.Speed;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Context;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LintUtils;
|
||||
import com.android.tools.klint.detector.api.Location;
|
||||
import com.android.tools.klint.detector.api.Project;
|
||||
import com.android.tools.klint.detector.api.ResourceXmlDetector;
|
||||
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 com.android.tools.klint.detector.api.XmlContext;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
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 java.awt.Dimension;
|
||||
@@ -99,24 +102,11 @@ import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
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
|
||||
* 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;
|
||||
static {
|
||||
@@ -158,7 +148,7 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
||||
* 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,
|
||||
Scope.JAVA_FILE, Scope.MANIFEST);
|
||||
Scope.SOURCE_FILE, Scope.MANIFEST);
|
||||
|
||||
private static final Implementation IMPLEMENTATION_JAVA = new Implementation(
|
||||
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_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 SET_SMALL_ICON = "setSmallIcon"; //$NON-NLS-1$
|
||||
private static final String ON_CREATE_OPTIONS_MENU = "onCreateOptionsMenu"; //$NON-NLS-1$
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
|
||||
return new NotificationFinder();
|
||||
public UastVisitor createUastVisitor(UastAndroidContext context) {
|
||||
return new NotificationFinder(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
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 UastVisitor {
|
||||
private UastAndroidContext mContext;
|
||||
|
||||
private final class NotificationFinder extends ForwardingAstVisitor {
|
||||
@Override
|
||||
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);
|
||||
public NotificationFinder(UastAndroidContext mContext) {
|
||||
this.mContext = mContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitConstructorInvocation(ConstructorInvocation node) {
|
||||
TypeReference reference = node.astTypeReference();
|
||||
StrictListAccessor<TypeReferencePart, TypeReference> parts = reference.astParts();
|
||||
String typeName = parts.last().astIdentifier().astValue();
|
||||
public boolean visitFunction(@NotNull UFunction node) {
|
||||
if (node.matchesName(ON_CREATE_OPTIONS_MENU)) {
|
||||
// Gather any R.menu references found in this method
|
||||
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)) {
|
||||
StrictListAccessor<Expression, ConstructorInvocation> args = node.astArguments();
|
||||
List<UExpression> args = node.getValueArguments();
|
||||
if (args.size() == 3) {
|
||||
if (args.first() instanceof Select && handleSelect((Select) args.first())) {
|
||||
return super.visitConstructorInvocation(node);
|
||||
if (args.get(0) instanceof UQualifiedExpression
|
||||
&& handleSelect((UQualifiedExpression) args.get(0))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node method = StringFormatDetector.getParentMethod(node);
|
||||
UFunction method = UastUtils.getContainingFunction(node);
|
||||
if (method != null) {
|
||||
// Must track local types
|
||||
String name = StringFormatDetector.getResourceForFirstArg(method, node);
|
||||
@@ -2024,31 +2028,24 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
||||
}
|
||||
}
|
||||
} else if (BUILDER_CLASS.equals(typeName)) {
|
||||
boolean isBuilder = false;
|
||||
if (parts.size() == 1) {
|
||||
isBuilder = true;
|
||||
} else if (parts.size() == 2) {
|
||||
String clz = parts.first().astIdentifier().astValue();
|
||||
if (NOTIFICATION_CLASS.equals(clz) || NOTIFICATION_COMPAT_CLASS.equals(clz)) {
|
||||
isBuilder = true;
|
||||
}
|
||||
}
|
||||
UClass resolvedClass = reference.resolveClass(mContext);
|
||||
boolean isBuilder = resolvedClass != null
|
||||
&& (resolvedClass.matchesFqName(NOTIFICATION_CLASS_FQNAME)
|
||||
|| resolvedClass.matchesFqName(NOTIFICATION_COMPAT_CLASS_FQNAME));
|
||||
if (isBuilder) {
|
||||
Node method = StringFormatDetector.getParentMethod(node);
|
||||
UFunction method = UastUtils.getContainingFunction(node);
|
||||
if (method != null) {
|
||||
SetIconFinder finder = new SetIconFinder();
|
||||
method.accept(finder);
|
||||
finder.process(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitConstructorInvocation(node);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleSelect(Select select) {
|
||||
if (select.toString().startsWith(R_DRAWABLE_PREFIX)) {
|
||||
String name = select.astIdentifier().astValue();
|
||||
private boolean handleSelect(UQualifiedExpression select) {
|
||||
if (select.renderString().startsWith(R_DRAWABLE_PREFIX)) {
|
||||
String name = select.getSelector().renderString();
|
||||
if (mNotificationIcons == null) {
|
||||
mNotificationIcons = Sets.newHashSet();
|
||||
}
|
||||
@@ -2060,32 +2057,31 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
|
||||
return false;
|
||||
}
|
||||
|
||||
private final class SetIconFinder extends ForwardingAstVisitor {
|
||||
private final class SetIconFinder extends UastVisitor {
|
||||
@Override
|
||||
public boolean visitMethodInvocation(MethodInvocation node) {
|
||||
if (SET_SMALL_ICON.equals(node.astName().astValue())) {
|
||||
StrictListAccessor<Expression,MethodInvocation> arguments = node.astArguments();
|
||||
if (arguments.size() == 1 && arguments.first() instanceof Select) {
|
||||
handleSelect((Select) arguments.first());
|
||||
public boolean visitCallExpression(@NotNull UCallExpression node) {
|
||||
if (SET_SMALL_ICON.equals(node.getFunctionName())) {
|
||||
List<UExpression> args = node.getValueArguments();
|
||||
if (args.size() == 1 && args.get(0) instanceof UQualifiedExpression) {
|
||||
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
|
||||
public boolean visitSelect(Select node) {
|
||||
public boolean visitQualifiedExpression(@NotNull UQualifiedExpression node) {
|
||||
// R.type.name
|
||||
if (node.astOperand() instanceof Select) {
|
||||
Select select = (Select) node.astOperand();
|
||||
if (select.astOperand() instanceof VariableReference) {
|
||||
VariableReference reference = (VariableReference) select.astOperand();
|
||||
if (reference.astIdentifier().astValue().equals(R_CLASS)) {
|
||||
String type = select.astIdentifier().astValue();
|
||||
|
||||
if (type.equals(MENU_TYPE)) {
|
||||
String name = node.astIdentifier().astValue();
|
||||
if (node.getReceiver() instanceof UQualifiedExpression) {
|
||||
UQualifiedExpression select = (UQualifiedExpression) node.getReceiver();
|
||||
if (select.getReceiver() instanceof USimpleReferenceExpression) {
|
||||
USimpleReferenceExpression reference = (USimpleReferenceExpression) select.getReceiver();
|
||||
if (R_CLASS.equals(reference.getIdentifier())) {
|
||||
if (select.selectorMatches(MENU_TYPE)) {
|
||||
String name = node.getSelector().renderString();
|
||||
// Reclassify icons in the given menu as action bar icons
|
||||
if (mMenuToIcons != null) {
|
||||
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
|
||||
* 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.ATTR_LAYOUT_HEIGHT;
|
||||
@@ -23,13 +23,13 @@ import static com.android.SdkConstants.VIEW_INCLUDE;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
import com.android.tools.lint.detector.api.Implementation;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.android.tools.lint.detector.api.LayoutDetector;
|
||||
import com.android.tools.lint.detector.api.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.XmlContext;
|
||||
import com.android.tools.klint.detector.api.Category;
|
||||
import com.android.tools.klint.detector.api.Implementation;
|
||||
import com.android.tools.klint.detector.api.Issue;
|
||||
import com.android.tools.klint.detector.api.LayoutDetector;
|
||||
import com.android.tools.klint.detector.api.Scope;
|
||||
import com.android.tools.klint.detector.api.Severity;
|
||||
import com.android.tools.klint.detector.api.XmlContext;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
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