Lint: Make lint run normally on both older and newer versions of IDEA (IdeaAndroidProject was replaced by AndroidGradleModel)
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="android-annotations" />
|
||||
<orderEntry type="module" module-name="lint-api" />
|
||||
<orderEntry type="module" module-name="lint-idea" />
|
||||
<orderEntry type="library" name="android-plugin" level="project" />
|
||||
<orderEntry type="library" name="guava" level="project" />
|
||||
<orderEntry type="module" module-name="uast-android" />
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<orderEntry type="module" module-name="lint-api" />
|
||||
<orderEntry type="module" module-name="lint-checks" />
|
||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
||||
<orderEntry type="library" name="kotlin-reflect" level="project" />
|
||||
<orderEntry type="library" name="idea-full" level="project" />
|
||||
<orderEntry type="module" module-name="uast-android" />
|
||||
<orderEntry type="module" module-name="uast-kotlin" />
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 org.jetbrains.android.inspections.klint
|
||||
|
||||
import com.android.builder.model.AndroidProject
|
||||
import com.android.builder.model.SourceProvider
|
||||
import com.android.builder.model.Variant
|
||||
import com.android.tools.idea.gradle.util.GradleUtil
|
||||
import org.jetbrains.android.facet.AndroidFacet
|
||||
import kotlin.reflect.memberFunctions
|
||||
import kotlin.reflect.staticFunctions
|
||||
|
||||
class AndroidModelFacade(val facet: AndroidFacet) {
|
||||
private val model by lazy { loadModel() }
|
||||
private val modelClass by lazy {
|
||||
try {
|
||||
Class.forName("com.android.tools.idea.gradle.AndroidGradleModel")
|
||||
}
|
||||
catch(e: ClassNotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun isModelReady() = model != null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun getFlavorSourceProviders(): List<SourceProvider>?
|
||||
= getFacetOrModel("getFlavorSourceProviders") as? List<SourceProvider>
|
||||
|
||||
fun getMultiFlavorSourceProvider(): SourceProvider?
|
||||
= getFacetOrModel("getMultiFlavorSourceProvider") as? SourceProvider
|
||||
|
||||
fun getBuildTypeSourceProvider(): SourceProvider?
|
||||
= getFacetOrModel("getBuildTypeSourceProvider") as? SourceProvider
|
||||
|
||||
fun getVariantSourceProvider(): SourceProvider?
|
||||
= getFacetOrModel("getVariantSourceProvider") as? SourceProvider
|
||||
|
||||
private fun getFacetOrModel(methodName: String): Any? {
|
||||
if (modelClass == null) {
|
||||
return facet.javaClass.kotlin.memberFunctions
|
||||
.firstOrNull { it.name == methodName }
|
||||
?.call(facet)
|
||||
}
|
||||
|
||||
return modelClass?.kotlin?.memberFunctions
|
||||
?.firstOrNull { it.name == methodName }
|
||||
?.call(model)
|
||||
}
|
||||
|
||||
fun getDependsOn(artifact: String): Boolean {
|
||||
val model = model ?: return false
|
||||
return GradleUtil::class.staticFunctions.firstOrNull {
|
||||
val type = it.parameters[0].type.toString()
|
||||
it.parameters.size == 2 && "IdeaAndroidProject" in type || "AndroidGradleModel" in type
|
||||
}?.call(model, artifact) as? Boolean ?: false
|
||||
}
|
||||
|
||||
fun getAndroidProject(): AndroidProject? {
|
||||
val model = model ?: return null
|
||||
return modelClass?.kotlin?.memberFunctions
|
||||
?.firstOrNull { it.name == "getDelegate" || it.name == "getAndroidProject" }
|
||||
?.call(model) as? AndroidProject
|
||||
}
|
||||
|
||||
fun getSelectedVariant(): Variant? {
|
||||
val model = model ?: return null
|
||||
return modelClass?.kotlin?.memberFunctions
|
||||
?.firstOrNull { it.name == "getSelectedVariant" }
|
||||
?.call(model) as? Variant
|
||||
}
|
||||
|
||||
private fun loadModel(): Any? {
|
||||
try {
|
||||
val getAndroidProjectInfoFun = AndroidFacet::class.memberFunctions.singleOrNull {
|
||||
it.name == "getIdeaAndroidProject" || it.name == "getAndroidModel"
|
||||
}
|
||||
|
||||
return getAndroidProjectInfoFun?.call(facet)
|
||||
}
|
||||
catch(e: Throwable) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun computePackageName(): String? {
|
||||
return getSelectedVariant()?.mainArtifact?.applicationId
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -382,9 +382,9 @@ public class IntellijLintClient extends com.android.tools.klint.client.api.LintC
|
||||
Module module = getModule();
|
||||
if (module != null) {
|
||||
AndroidFacet facet = AndroidFacet.getInstance(module);
|
||||
return facet != null && facet.isGradleProject();
|
||||
return facet != null && IntellijLintUtils.isGradleModule(facet);
|
||||
}
|
||||
return Projects.isGradleProject(myProject);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+44
-51
@@ -19,7 +19,6 @@ import com.android.annotations.NonNull;
|
||||
import com.android.builder.model.*;
|
||||
import com.android.sdklib.AndroidTargetHash;
|
||||
import com.android.sdklib.AndroidVersion;
|
||||
import com.android.tools.idea.gradle.IdeaAndroidProject;
|
||||
import com.android.tools.idea.gradle.util.GradleUtil;
|
||||
import com.android.tools.idea.model.AndroidModuleInfo;
|
||||
import com.android.tools.idea.model.ManifestInfo;
|
||||
@@ -54,6 +53,7 @@ import java.util.*;
|
||||
|
||||
import static com.android.SdkConstants.APPCOMPAT_LIB_ARTIFACT;
|
||||
import static com.android.SdkConstants.SUPPORT_LIB_ARTIFACT;
|
||||
import static org.jetbrains.android.inspections.klint.IntellijLintUtils.*;
|
||||
|
||||
/**
|
||||
* An {@linkplain IntellijLintProject} represents a lint project, which typically corresponds to a {@link Module},
|
||||
@@ -245,7 +245,7 @@ class IntellijLintProject extends Project {
|
||||
}
|
||||
|
||||
AndroidFacet facet = AndroidFacet.getInstance(module);
|
||||
if (facet != null && facet.isGradleProject()) {
|
||||
if (facet != null && isGradleModule(facet)) {
|
||||
addGradleLibraryProjects(client, files, libraryMap, projects, facet, project, projectMap, dependencies);
|
||||
}
|
||||
|
||||
@@ -301,10 +301,10 @@ class IntellijLintProject extends Project {
|
||||
project = new LintModuleProject(client, dir, dir, module);
|
||||
AndroidFacet f = findAndroidFacetInProject(module.getProject());
|
||||
if (f != null) {
|
||||
project.mGradleProject = f.isGradleProject();
|
||||
project.mGradleProject = isGradleModule(f);
|
||||
}
|
||||
}
|
||||
else if (facet.isGradleProject()) {
|
||||
else if (isGradleModule((facet))) {
|
||||
project = new LintGradleProject(client, dir, dir, facet);
|
||||
}
|
||||
else {
|
||||
@@ -340,9 +340,11 @@ class IntellijLintProject extends Project {
|
||||
@NonNull LintModuleProject project,
|
||||
@NonNull Map<Project,Module> projectMap,
|
||||
@NonNull List<Project> dependencies) {
|
||||
File dir;IdeaAndroidProject gradleProject = facet.getIdeaAndroidProject();
|
||||
if (gradleProject != null) {
|
||||
Collection<AndroidLibrary> libraries = gradleProject.getSelectedVariant().getMainArtifact().getDependencies().getLibraries();
|
||||
File dir;
|
||||
AndroidModelFacade androidModelFacade = getModelFacade(facet);
|
||||
Variant selectedVariant = androidModelFacade.getSelectedVariant();
|
||||
if (selectedVariant != null) {
|
||||
Collection<AndroidLibrary> libraries = selectedVariant.getMainArtifact().getDependencies().getLibraries();
|
||||
for (AndroidLibrary library : libraries) {
|
||||
Project p = libraryMap.get(library);
|
||||
if (p == null) {
|
||||
@@ -540,7 +542,7 @@ class IntellijLintProject extends Project {
|
||||
@Override
|
||||
public List<File> getProguardFiles() {
|
||||
if (mProguardFiles == null) {
|
||||
assert !myFacet.isGradleProject(); // Should be overridden to read from gradle state
|
||||
assert !isGradleModule(myFacet); // Should be overridden to read from gradle state
|
||||
final JpsAndroidModuleProperties properties = myFacet.getProperties();
|
||||
|
||||
if (properties.RUN_PROGUARD) {
|
||||
@@ -659,7 +661,7 @@ class IntellijLintProject extends Project {
|
||||
mManifestFiles.add(mainManifest);
|
||||
}
|
||||
|
||||
List<SourceProvider> flavorSourceProviders = myFacet.getFlavorSourceProviders();
|
||||
List<SourceProvider> flavorSourceProviders = getModelFacade(myFacet).getFlavorSourceProviders();
|
||||
if (flavorSourceProviders != null) {
|
||||
for (SourceProvider provider : flavorSourceProviders) {
|
||||
File manifestFile = provider.getManifestFile();
|
||||
@@ -669,7 +671,7 @@ class IntellijLintProject extends Project {
|
||||
}
|
||||
}
|
||||
|
||||
SourceProvider multiProvider = myFacet.getMultiFlavorSourceProvider();
|
||||
SourceProvider multiProvider = getModelFacade(myFacet).getMultiFlavorSourceProvider();
|
||||
if (multiProvider != null) {
|
||||
File manifestFile = multiProvider.getManifestFile();
|
||||
if (manifestFile.exists()) {
|
||||
@@ -677,7 +679,7 @@ class IntellijLintProject extends Project {
|
||||
}
|
||||
}
|
||||
|
||||
SourceProvider buildTypeSourceProvider = myFacet.getBuildTypeSourceProvider();
|
||||
SourceProvider buildTypeSourceProvider = getModelFacade(myFacet).getBuildTypeSourceProvider();
|
||||
if (buildTypeSourceProvider != null) {
|
||||
File manifestFile = buildTypeSourceProvider.getManifestFile();
|
||||
if (manifestFile.exists()) {
|
||||
@@ -685,7 +687,7 @@ class IntellijLintProject extends Project {
|
||||
}
|
||||
}
|
||||
|
||||
SourceProvider variantProvider = myFacet.getVariantSourceProvider();
|
||||
SourceProvider variantProvider = getModelFacade(myFacet).getVariantSourceProvider();
|
||||
if (variantProvider != null) {
|
||||
File manifestFile = variantProvider.getManifestFile();
|
||||
if (manifestFile.exists()) {
|
||||
@@ -701,10 +703,11 @@ class IntellijLintProject extends Project {
|
||||
@Override
|
||||
public List<File> getProguardFiles() {
|
||||
if (mProguardFiles == null) {
|
||||
if (myFacet.isGradleProject()) {
|
||||
IdeaAndroidProject gradleProject = myFacet.getIdeaAndroidProject();
|
||||
if (gradleProject != null) {
|
||||
ProductFlavor flavor = gradleProject.getDelegate().getDefaultConfig().getProductFlavor();
|
||||
if (isGradleModule(myFacet)) {
|
||||
AndroidModelFacade androidModelFacade = getModelFacade(myFacet);
|
||||
AndroidProject androidProject = androidModelFacade.getAndroidProject();
|
||||
if (androidProject != null) {
|
||||
ProductFlavor flavor = androidProject.getDefaultConfig().getProductFlavor();
|
||||
mProguardFiles = Lists.newArrayList();
|
||||
for (File file : flavor.getProguardFiles()) {
|
||||
if (file.exists()) {
|
||||
@@ -742,10 +745,10 @@ class IntellijLintProject extends Project {
|
||||
// the AndroidDexCompiler settings the way java source roots are mapped into
|
||||
// the module content root settings
|
||||
File dir = null;
|
||||
if (myFacet.isGradleProject()) {
|
||||
IdeaAndroidProject gradleProject = myFacet.getIdeaAndroidProject();
|
||||
if (gradleProject != null) {
|
||||
Variant variant = gradleProject.getSelectedVariant();
|
||||
if (isGradleModule(myFacet)) {
|
||||
AndroidModelFacade androidModelFacade = getModelFacade(myFacet);
|
||||
Variant variant = androidModelFacade.getSelectedVariant();
|
||||
if (variant != null) {
|
||||
dir = variant.getMainArtifact().getClassesFolder();
|
||||
}
|
||||
}
|
||||
@@ -767,9 +770,10 @@ class IntellijLintProject extends Project {
|
||||
public List<File> getJavaLibraries() {
|
||||
if (SUPPORT_CLASS_FILES) {
|
||||
if (mJavaLibraries == null) {
|
||||
if (myFacet.isGradleProject() && myFacet.getIdeaAndroidProject() != null) {
|
||||
IdeaAndroidProject gradleProject = myFacet.getIdeaAndroidProject();
|
||||
Collection<JavaLibrary> libs = gradleProject.getSelectedVariant().getMainArtifact().getDependencies().getJavaLibraries();
|
||||
AndroidModelFacade androidModelFacade = getModelFacade(myFacet);
|
||||
Variant selectedVariant = androidModelFacade.getSelectedVariant();
|
||||
if (isGradleModule(myFacet) && selectedVariant != null) {
|
||||
Collection<JavaLibrary> libs = selectedVariant.getMainArtifact().getDependencies().getJavaLibraries();
|
||||
mJavaLibraries = Lists.newArrayListWithExpectedSize(libs.size());
|
||||
for (JavaLibrary lib : libs) {
|
||||
File jar = lib.getJarFile();
|
||||
@@ -798,12 +802,7 @@ class IntellijLintProject extends Project {
|
||||
return manifestPackage;
|
||||
}
|
||||
|
||||
IdeaAndroidProject project = myFacet.getIdeaAndroidProject();
|
||||
if (project != null) {
|
||||
return project.computePackageName();
|
||||
}
|
||||
|
||||
return null;
|
||||
return getModelFacade(myFacet).computePackageName();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -828,9 +827,10 @@ class IntellijLintProject extends Project {
|
||||
|
||||
@Override
|
||||
public int getBuildSdk() {
|
||||
IdeaAndroidProject ideaAndroidProject = myFacet.getIdeaAndroidProject();
|
||||
if (ideaAndroidProject != null) {
|
||||
String compileTarget = ideaAndroidProject.getDelegate().getCompileTarget();
|
||||
AndroidModelFacade androidModelFacade = getModelFacade(myFacet);
|
||||
AndroidProject androidProject = androidModelFacade.getAndroidProject();
|
||||
if (androidProject != null) {
|
||||
String compileTarget = androidProject.getCompileTarget();
|
||||
AndroidVersion version = AndroidTargetHash.getPlatformVersion(compileTarget);
|
||||
if (version != null) {
|
||||
return version.getApiLevel();
|
||||
@@ -848,24 +848,14 @@ class IntellijLintProject extends Project {
|
||||
@Nullable
|
||||
@Override
|
||||
public AndroidProject getGradleProjectModel() {
|
||||
IdeaAndroidProject project = myFacet.getIdeaAndroidProject();
|
||||
if (project != null) {
|
||||
project.getSelectedVariant();
|
||||
return project.getDelegate();
|
||||
}
|
||||
|
||||
return null;
|
||||
AndroidModelFacade androidModelFacade = getModelFacade(myFacet);
|
||||
return androidModelFacade.getAndroidProject();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Variant getCurrentVariant() {
|
||||
IdeaAndroidProject project = myFacet.getIdeaAndroidProject();
|
||||
if (project != null) {
|
||||
return project.getSelectedVariant();
|
||||
}
|
||||
|
||||
return null;
|
||||
return getModelFacade(myFacet).getSelectedVariant();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -879,8 +869,9 @@ class IntellijLintProject extends Project {
|
||||
public Boolean dependsOn(@NonNull String artifact) {
|
||||
if (SUPPORT_LIB_ARTIFACT.equals(artifact)) {
|
||||
if (mSupportLib == null) {
|
||||
if (myFacet.isGradleProject() && myFacet.getIdeaAndroidProject() != null) {
|
||||
mSupportLib = GradleUtil.dependsOn(myFacet.getIdeaAndroidProject(), artifact);
|
||||
AndroidModelFacade facade = getModelFacade(myFacet);
|
||||
if (isGradleModule(myFacet) && facade.isModelReady()) {
|
||||
mSupportLib = facade.getDependsOn(artifact);
|
||||
} else {
|
||||
mSupportLib = depsDependsOn(this, artifact);
|
||||
}
|
||||
@@ -888,8 +879,9 @@ class IntellijLintProject extends Project {
|
||||
return mSupportLib;
|
||||
} else if (APPCOMPAT_LIB_ARTIFACT.equals(artifact)) {
|
||||
if (mAppCompat == null) {
|
||||
if (myFacet.isGradleProject() && myFacet.getIdeaAndroidProject() != null) {
|
||||
mAppCompat = GradleUtil.dependsOn(myFacet.getIdeaAndroidProject(), artifact);
|
||||
AndroidModelFacade facade = getModelFacade(myFacet);
|
||||
if (isGradleModule(myFacet) && facade.isModelReady()) {
|
||||
mAppCompat = facade.getDependsOn(artifact);
|
||||
} else {
|
||||
mAppCompat = depsDependsOn(this, artifact);
|
||||
}
|
||||
@@ -897,8 +889,9 @@ class IntellijLintProject extends Project {
|
||||
return mAppCompat;
|
||||
} else {
|
||||
// Some other (not yet directly cached result)
|
||||
if (myFacet.isGradleProject() && myFacet.getIdeaAndroidProject() != null
|
||||
&& GradleUtil.dependsOn(myFacet.getIdeaAndroidProject(), artifact)) {
|
||||
AndroidModelFacade facade = getModelFacade(myFacet);
|
||||
if (isGradleModule(myFacet) && facade.isModelReady()
|
||||
&& facade.getDependsOn(artifact)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+29
-3
@@ -22,7 +22,11 @@ import com.android.builder.model.SourceProvider;
|
||||
import com.android.tools.klint.client.api.LintRequest;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.intellij.debugger.engine.JVMNameUtil;
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.ide.util.JavaAnonymousClassesHelper;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -61,6 +65,8 @@ public class IntellijLintUtils {
|
||||
@NonNls
|
||||
public static final String SUPPRESS_WARNINGS_FQCN = "java.lang.SuppressWarnings";
|
||||
|
||||
private static final ProjectSystemId GRADLE_ID = new ProjectSystemId("GRADLE");
|
||||
|
||||
/**
|
||||
* Gets the location of the given element
|
||||
*
|
||||
@@ -362,13 +368,33 @@ public class IntellijLintUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isProjectReady(AndroidFacet facet) {
|
||||
try {
|
||||
return AndroidFacet.class.getMethod("getIdeaAndroidProject", AndroidFacet.class).invoke(facet) != null;
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return AndroidFacet.class.getMethod("getAndroidModel", AndroidFacet.class).invoke(facet) != null;
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static AndroidModelFacade getModelFacade(AndroidFacet facet) {
|
||||
return new AndroidModelFacade(facet);
|
||||
}
|
||||
|
||||
public static boolean isGradleModule(Facet<?> facet) {
|
||||
Module module = facet.getModule();
|
||||
return ExternalSystemApiUtil.isExternalSystemAwareModule(GRADLE_ID, module);
|
||||
}
|
||||
|
||||
/** Returns the resource directories to use for the given module */
|
||||
@NotNull
|
||||
public static List<File> getResourceDirectories(@NotNull AndroidFacet facet) {
|
||||
if (facet.isGradleProject()) {
|
||||
if (isGradleModule(facet)) {
|
||||
List<File> resDirectories = new ArrayList<File>();
|
||||
resDirectories.addAll(facet.getMainSourceProvider().getResDirectories());
|
||||
List<SourceProvider> flavorSourceProviders = facet.getFlavorSourceProviders();
|
||||
List<SourceProvider> flavorSourceProviders = getModelFacade(facet).getFlavorSourceProviders();
|
||||
if (flavorSourceProviders != null) {
|
||||
for (SourceProvider provider : flavorSourceProviders) {
|
||||
for (File file : provider.getResDirectories()) {
|
||||
@@ -379,7 +405,7 @@ public class IntellijLintUtils {
|
||||
}
|
||||
}
|
||||
|
||||
SourceProvider buildTypeSourceProvider = facet.getBuildTypeSourceProvider();
|
||||
SourceProvider buildTypeSourceProvider = getModelFacade(facet).getBuildTypeSourceProvider();
|
||||
if (buildTypeSourceProvider != null) {
|
||||
for (File file : buildTypeSourceProvider.getResDirectories()) {
|
||||
if (file.isDirectory()) {
|
||||
|
||||
Reference in New Issue
Block a user