Lint: Make lint run normally on both older and newer versions of IDEA (IdeaAndroidProject was replaced by AndroidGradleModel)

This commit is contained in:
Yan Zhulanow
2016-04-01 16:44:26 +03:00
parent 726bfca540
commit 991e783ccf
6 changed files with 197 additions and 56 deletions
+1
View File
@@ -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" />
+1
View File
@@ -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" />
@@ -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
}
}
@@ -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
@@ -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;
}
@@ -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()) {