Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2012-04-23 16:49:45 +02:00
20 changed files with 476 additions and 127 deletions
@@ -78,8 +78,9 @@ public class PsiTypeLookupItem extends LookupItem {
PsiElement position = context.getFile().findElementAt(context.getStartOffset());
assert position != null;
context.getDocument().insertString(context.getTailOffset(), calcGenerics(position, context));
JavaCompletionUtil.shortenReference(context.getFile(), context.getStartOffset());
int genericsStart = context.getTailOffset();
context.getDocument().insertString(genericsStart, calcGenerics(position, context));
JavaCompletionUtil.shortenReference(context.getFile(), genericsStart - 1);
int tail = context.getTailOffset();
String braces = StringUtil.repeat("[]", getBracketsCount());
@@ -595,16 +595,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
if (dfaRight instanceof DfaNotNullValue) {
if (dfaLeft instanceof DfaVariableValue) {
DfaVariableState varState = getVariableState((DfaVariableValue)dfaLeft);
DfaVariableValue dfaVar = (DfaVariableValue)dfaLeft;
DfaTypeValue type = myFactory.getTypeFactory().create(((DfaNotNullValue)dfaRight).getType());
if (isNegated) {
return applyCondition(myFactory.getRelationFactory().create(dfaVar, DfaUnknownValue.getInstance(), JavaTokenType.EQEQ, false));
}
return applyCondition(compareToNull(dfaVar, false)) && varState.setInstanceofValue(type);
}
return true;
}
@@ -0,0 +1,14 @@
public class Test {
{
new Foo<String>().method(new Outer.Inner<String>());<caret>
}
static class Outer {
static class Inner<A> {}
}
class Foo<A> {
public void method(Outer.Inner<A> inner) {}
}
}
@@ -0,0 +1,14 @@
public class Test {
{
new Foo<String>().method(new <caret>);
}
static class Outer {
static class Inner<A> {}
}
class Foo<A> {
public void method(Outer.Inner<A> inner) {}
}
}
@@ -0,0 +1,26 @@
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public class Bar3 {
@NotNull
Object getObj() {
return new Object();
}
void foo(Collection<Object> collection) {
if (!collection.isEmpty()) {
Object first = collection.iterator().next();
if (first != getObj() || collection.size() > 0) {
System.out.println(first.hashCode());
}
if (first == getObj() || collection.size() > 0) {
System.out.println(first.hashCode());
}
if (first == null) {
System.out.println(<warning descr="Method invocation 'first.hashCode()' may produce 'java.lang.NullPointerException'">first.hashCode()</warning>);
}
}
}
}
@@ -1034,6 +1034,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
public void testArrayInitializerBeforeVarargs() throws Throwable { doTest(); }
public void testDuplicateMembersFromSuperClass() throws Throwable { doTest(); }
public void testInnerAfterNew() throws Throwable { doTest(); }
public void testMemberImportStatically() {
configureByTestName();
@@ -61,5 +61,6 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas
public void testGeneratedEquals() throws Throwable { doTest(); }
public void testIDEA84489() throws Throwable { doTest(); }
public void testComparingToNotNullShouldNotAffectNullity() throws Throwable { doTest(); }
}
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2010 Bas Leijdekkers
* Copyright 2009-2012 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,13 +19,13 @@ import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.ClassUtils;
import com.siyeh.ig.psiutils.HighlightUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
@@ -34,12 +34,10 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.HashSet;
public class DynamicRegexReplaceableByCompiledPatternInspection
extends BaseInspection {
public class DynamicRegexReplaceableByCompiledPatternInspection extends BaseInspection {
@NonNls
private static final Collection<String> regexMethodNames =
new HashSet(4);
private static final Collection<String> regexMethodNames = new HashSet(4);
static {
regexMethodNames.add("matches");
@@ -73,8 +71,7 @@ public class DynamicRegexReplaceableByCompiledPatternInspection
return new DynamicRegexReplaceableByCompiledPatternFix();
}
private static class DynamicRegexReplaceableByCompiledPatternFix
extends InspectionGadgetsFix {
private static class DynamicRegexReplaceableByCompiledPatternFix extends InspectionGadgetsFix {
@NotNull
public String getName() {
@@ -86,8 +83,7 @@ public class DynamicRegexReplaceableByCompiledPatternInspection
protected void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final PsiElement element = descriptor.getPsiElement();
final PsiClass aClass = PsiTreeUtil.getParentOfType(element,
PsiClass.class);
final PsiClass aClass = ClassUtils.getContainingStaticClass(element);
if (aClass == null) {
return;
}
@@ -95,38 +91,28 @@ public class DynamicRegexReplaceableByCompiledPatternInspection
if (!(parent instanceof PsiReferenceExpression)) {
return;
}
final PsiReferenceExpression methodExpression =
(PsiReferenceExpression)parent;
final PsiReferenceExpression methodExpression = (PsiReferenceExpression)parent;
final PsiElement grandParent = methodExpression.getParent();
if (!(grandParent instanceof PsiMethodCallExpression)) {
return;
}
final PsiMethodCallExpression methodCallExpression =
(PsiMethodCallExpression)grandParent;
final PsiExpressionList list =
methodCallExpression.getArgumentList();
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent;
final PsiExpressionList list = methodCallExpression.getArgumentList();
final PsiExpression[] expressions = list.getExpressions();
@NonNls final StringBuilder fieldText =
new StringBuilder(
"private static final java.util.regex.Pattern PATTERN = " +
"java.util.regex.Pattern.compile(");
new StringBuilder("private static final java.util.regex.Pattern PATTERN = java.util.regex.Pattern.compile(");
final int expressionsLength = expressions.length;
if (expressionsLength > 0) {
fieldText.append(expressions[0].getText());
}
fieldText.append(");");
final PsiElementFactory factory =
JavaPsiFacade.getElementFactory(project);
final PsiField newField =
factory.createFieldFromText(fieldText.toString(), element);
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final PsiField newField = factory.createFieldFromText(fieldText.toString(), element);
final PsiElement field = aClass.add(newField);
@NonNls final StringBuilder expressionText =
new StringBuilder("PATTERN.");
@NonNls final String methodName =
methodExpression.getReferenceName();
final PsiExpression qualifier =
methodExpression.getQualifierExpression();
@NonNls final StringBuilder expressionText = new StringBuilder("PATTERN.");
@NonNls final String methodName = methodExpression.getReferenceName();
final PsiExpression qualifier = methodExpression.getQualifierExpression();
@NonNls final String qualifierText;
if (qualifier == null) {
qualifierText = "this";
@@ -160,30 +146,18 @@ public class DynamicRegexReplaceableByCompiledPatternInspection
expressionText.append(')');
}
final PsiExpression newExpression =
factory.createExpressionFromText(expressionText.toString(),
element);
PsiMethodCallExpression newMethodCallExpression =
(PsiMethodCallExpression)methodCallExpression.replace(
newExpression);
newMethodCallExpression =
CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(
newMethodCallExpression);
final PsiReferenceExpression reference =
getReference(newMethodCallExpression);
HighlightUtils.showRenameTemplate(aClass,
(PsiNameIdentifierOwner)field, reference);
final PsiExpression newExpression = factory.createExpressionFromText(expressionText.toString(), element);
PsiMethodCallExpression newMethodCallExpression = (PsiMethodCallExpression)methodCallExpression.replace(newExpression);
newMethodCallExpression = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(newMethodCallExpression);
final PsiReferenceExpression reference = getReference(newMethodCallExpression);
HighlightUtils.showRenameTemplate(aClass, (PsiNameIdentifierOwner)field, reference);
}
private static PsiReferenceExpression getReference(
PsiMethodCallExpression newMethodCallExpression) {
final PsiReferenceExpression methodExpression =
newMethodCallExpression.getMethodExpression();
final PsiExpression qualifierExpression =
methodExpression.getQualifierExpression();
private static PsiReferenceExpression getReference(PsiMethodCallExpression newMethodCallExpression) {
final PsiReferenceExpression methodExpression = newMethodCallExpression.getMethodExpression();
final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
if (qualifierExpression instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression methodCallExpression =
(PsiMethodCallExpression)qualifierExpression;
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)qualifierExpression;
return getReference(methodCallExpression);
}
if (!(qualifierExpression instanceof PsiReferenceExpression)) {
@@ -198,12 +172,10 @@ public class DynamicRegexReplaceableByCompiledPatternInspection
return new DynamicRegexReplaceableByCompiledPatternVisitor();
}
private static class DynamicRegexReplaceableByCompiledPatternVisitor
extends BaseInspectionVisitor {
private static class DynamicRegexReplaceableByCompiledPatternVisitor extends BaseInspectionVisitor {
@Override
public void visitMethodCallExpression(
PsiMethodCallExpression expression) {
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
if (!isCallToRegexMethod(expression)) {
return;
@@ -212,10 +184,8 @@ public class DynamicRegexReplaceableByCompiledPatternInspection
}
private static boolean isCallToRegexMethod(
PsiMethodCallExpression expression) {
final PsiReferenceExpression methodExpression =
expression.getMethodExpression();
private static boolean isCallToRegexMethod(PsiMethodCallExpression expression) {
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
final String name = methodExpression.getReferenceName();
if (!regexMethodNames.contains(name)) {
return false;
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,14 +30,12 @@ public class ClassUtils {
/**
* @noinspection StaticCollection
*/
private static final Set<String> immutableTypes =
new HashSet<String>(19);
private static final Set<String> immutableTypes = new HashSet<String>(19);
/**
* @noinspection StaticCollection
*/
private static final Set<PsiType> primitiveNumericTypes =
new HashSet<PsiType>(7);
private static final Set<PsiType> primitiveNumericTypes = new HashSet<PsiType>(7);
/**
* @noinspection StaticCollection
@@ -170,6 +168,20 @@ public class ClassUtils {
}
}
@Nullable
public static PsiClass getContainingStaticClass(PsiElement element) {
PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
if (aClass == null) {
return null;
}
PsiClass containingClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
while (containingClass != null && !containingClass.hasModifierProperty(PsiModifier.STATIC) && !containingClass.isInterface()) {
aClass = containingClass;
containingClass = aClass.getContainingClass();
}
return aClass;
}
public static boolean isClassVisibleFromClass(PsiClass baseClass,
PsiClass referencedClass) {
if (referencedClass.hasModifierProperty(PsiModifier.PUBLIC)) {
@@ -53,8 +53,9 @@ public class AndroidCommonUtils {
private static final Pattern ERROR_PATTERN = Pattern.compile(".*error.*");
private static final Pattern EXCEPTION_PATTERN = Pattern.compile(".*exception.*");
private static Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class");
private static Pattern MANIFEST_PATTERN = Pattern.compile("Manifest(\\$.*)?\\.class");
private static final Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class");
private static final Pattern MANIFEST_PATTERN = Pattern.compile("Manifest(\\$.*)?\\.class");
private static final String BUILD_CONFIG_CLASS_NAME = "BuildConfig.class";
public static final Pattern COMPILER_MESSAGE_PATTERN = Pattern.compile("(.+):(\\d+):.+");
@@ -226,7 +227,8 @@ public class AndroidCommonUtils {
if (!packRAndManifestClasses &&
(R_PATTERN.matcher(file.getName()).matches() ||
MANIFEST_PATTERN.matcher(file.getName()).matches())) {
MANIFEST_PATTERN.matcher(file.getName()).matches() ||
BUILD_CONFIG_CLASS_NAME.equals(file.getName()))) {
return;
}
+1
View File
@@ -134,6 +134,7 @@
<compiler implementation="org.jetbrains.android.compiler.AndroidIncludingCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidRenderscriptCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidBuildConfigGeneratingCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidAptCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidIdlCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidLibraryPackagingCompiler"/>
@@ -26,8 +26,6 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.compiler.tools.AndroidApt;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
@@ -260,7 +258,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
-1, -1);
continue;
}
final String[] libPackages = getLibPackages(module, packageName);
final String[] libPackages = AndroidCompileUtil.getLibPackages(module, packageName);
final Module circularDepLibWithSamePackage = AndroidCompileUtil.findCircularDependencyOnLibraryWithSamePackage(facet);
if (circularDepLibWithSamePackage != null && !facet.getConfiguration().LIBRARY_PROJECT) {
@@ -304,22 +302,6 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler {
}
return false;
}
@NotNull
private static String[] getLibPackages(@NotNull Module module, @NotNull String packageName) {
final Set<String> packageSet = new HashSet<String>();
packageSet.add(packageName);
final List<String> result = new ArrayList<String>();
for (String libPackage : AndroidUtils.getDepLibsPackages(module)) {
if (packageSet.add(libPackage)) {
result.add(libPackage);
}
}
return ArrayUtil.toStringArray(result);
}
}
private static class MyValidityState extends ResourceNamesValidityState {
@@ -2,6 +2,7 @@ package org.jetbrains.android.compiler;
import com.android.AndroidConstants;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.build.BuildConfigGenerator;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.ModuleCompileScope;
import com.intellij.openapi.application.ApplicationManager;
@@ -58,6 +59,7 @@ public class AndroidAutogenerator {
case AIDL:
return facet.getConfiguration().REGENERATE_JAVA_BY_AIDL;
case RENDERSCRIPT:
case BUILDCONFIG:
return true;
default:
LOG.error("Unknown autogenerator mode " + mode);
@@ -81,6 +83,9 @@ public class AndroidAutogenerator {
case RENDERSCRIPT:
runRenderscript(facet, context);
break;
case BUILDCONFIG:
runBuildConfigGenerator(facet, context);
break;
default:
LOG.error("Unknown mode" + mode);
}
@@ -96,6 +101,80 @@ public class AndroidAutogenerator {
}
}
private static void runBuildConfigGenerator(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) {
final Module module = facet.getModule();
final BuildconfigAutogenerationItem item = ApplicationManager.getApplication().runReadAction(
new Computable<BuildconfigAutogenerationItem>() {
@Nullable
@Override
public BuildconfigAutogenerationItem compute() {
if (module.isDisposed() || module.getProject().isDisposed()) {
return null;
}
final String sourceRootPath = AndroidRootUtil.getBuildconfigGenSourceRootPath(facet);
if (sourceRootPath == null) {
return null;
}
final VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet);
if (manifestFile == null) {
context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("android.compilation.error.manifest.not.found"),
null, -1, -1);
return null;
}
final Manifest manifest = AndroidUtils.loadDomElement(module, manifestFile, Manifest.class);
if (manifest == null) {
context.addMessage(CompilerMessageCategory.ERROR, "Cannot parse file", manifestFile.getUrl(), -1, -1);
return null;
}
String packageName = manifest.getPackage().getValue();
if (packageName != null) {
packageName = packageName.trim();
}
if (packageName == null || packageName.length() <= 0) {
context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("package.not.found.error"), manifestFile.getUrl(),
-1, -1);
return null;
}
return new BuildconfigAutogenerationItem(packageName, FileUtil.toSystemDependentName(sourceRootPath));
}
});
// doesn't matter, because autogenerated class is used for resolve/completion only
final boolean debug = true;
final BuildConfigGenerator generator = new BuildConfigGenerator(item.mySourceRootOsPath, item.myPackage, debug);
try {
generator.generate();
final VirtualFile genSourceRoot = LocalFileSystem.getInstance().findFileByPath(item.mySourceRootOsPath);
if (genSourceRoot != null) {
genSourceRoot.refresh(false, true);
}
facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.BUILDCONFIG);
final VirtualFile genFile = LocalFileSystem.getInstance().findFileByPath(
item.mySourceRootOsPath + '/' + item.myPackage.replace('.', '/') + '/' + BuildConfigGenerator.BUILD_CONFIG_NAME);
if (genFile != null && genFile.exists()) {
facet.markFileAutogenerated(AndroidAutogeneratorMode.BUILDCONFIG, genFile);
}
}
catch (final IOException e) {
LOG.info(e);
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (module.getProject().isDisposed()) return;
context.addMessage(CompilerMessageCategory.ERROR, "I/O error: " + e.getMessage(), null, -1, -1);
}
});
}
}
private static void runAapt(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) {
final Module module = facet.getModule();
@@ -644,4 +723,14 @@ public class AndroidAutogenerator {
myRawDirPath = rawDirPath;
}
}
private static class BuildconfigAutogenerationItem {
final String myPackage;
final String mySourceRootOsPath;
private BuildconfigAutogenerationItem(@NotNull String aPackage, @NotNull String sourceRootOsPath) {
myPackage = aPackage;
mySourceRootOsPath = sourceRootOsPath;
}
}
}
@@ -4,5 +4,5 @@ package org.jetbrains.android.compiler;
* @author Eugene.Kudelevsky
*/
public enum AndroidAutogeneratorMode {
AAPT, AIDL, RENDERSCRIPT
AAPT, AIDL, RENDERSCRIPT, BUILDCONFIG
}
@@ -0,0 +1,193 @@
package org.jetbrains.android.compiler;
import com.android.sdklib.internal.build.BuildConfigGenerator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidBuildConfigGeneratingCompiler implements SourceGeneratingCompiler {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidBuildConfigGeneratingCompiler");
@Nullable
@Override
public VirtualFile getPresentableFile(CompileContext context, Module module, VirtualFile outputRoot, VirtualFile generatedFile) {
return null;
}
@Override
public GenerationItem[] getGenerationItems(final CompileContext context) {
return ApplicationManager.getApplication().runReadAction(new Computable<GenerationItem[]>() {
@Override
public GenerationItem[] compute() {
final List<GenerationItem> result = new ArrayList<GenerationItem>();
for (Module module : ModuleManager.getInstance(context.getProject()).getModules()) {
final AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet == null) {
continue;
}
final VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet);
if (manifestFile == null) {
context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("android.compilation.error.manifest.not.found"),
null, -1, -1);
continue;
}
final Manifest manifest = AndroidUtils.loadDomElement(module, manifestFile, Manifest.class);
if (manifest == null) {
context.addMessage(CompilerMessageCategory.ERROR, "Cannot parse file", manifestFile.getUrl(), -1, -1);
continue;
}
String packageName = manifest.getPackage().getValue();
if (packageName != null) {
packageName = packageName.trim();
}
if (packageName == null || packageName.length() <= 0) {
context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("package.not.found.error"), manifestFile.getUrl(),
-1, -1);
continue;
}
final boolean debug = !AndroidCompileUtil.isReleaseBuild(context);
result.add(new MyGenerationItem(module, packageName, debug));
for (String libPackage : AndroidCompileUtil.getLibPackages(module, packageName)) {
result.add(new MyGenerationItem(module, libPackage, debug));
}
}
return result.toArray(new GenerationItem[result.size()]);
}
});
}
@Override
public GenerationItem[] generate(CompileContext context,
GenerationItem[] items,
VirtualFile outputRootDirectory) {
if (items == null || items.length == 0) {
return new GenerationItem[0];
}
context.getProgressIndicator().setText("Generating BuildConfig.java...");
final String genFolderOsPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath());
final List<GenerationItem> result = new ArrayList<GenerationItem>();
for (GenerationItem item : items) {
final MyGenerationItem genItem = (MyGenerationItem)item;
final BuildConfigGenerator generator = new BuildConfigGenerator(genFolderOsPath, genItem.myPackage, genItem.myDebug);
try {
generator.generate();
result.add(genItem);
}
catch (IOException e) {
context.addMessage(CompilerMessageCategory.ERROR, "I/O error: " + e.getMessage(), null, -1, -1);
LOG.info(e);
}
}
if (result.size() > 0) {
outputRootDirectory.refresh(false, true);
}
return result.toArray(new GenerationItem[result.size()]);
}
@NotNull
@Override
public String getDescription() {
return "Android BuildConfig Generator";
}
@Override
public boolean validateConfiguration(CompileScope scope) {
return true;
}
@Override
public ValidityState createValidityState(DataInput in) throws IOException {
return new MyValidityState(in);
}
private static class MyGenerationItem implements GenerationItem{
final Module myModule;
final String myPackage;
final boolean myDebug;
private MyGenerationItem(@NotNull Module module, @NotNull String aPackage, boolean debug) {
myModule = module;
myPackage = aPackage;
myDebug = debug;
}
@Override
public String getPath() {
return myPackage.replace('.', '/') + '/' + BuildConfigGenerator.BUILD_CONFIG_NAME;
}
@Override
public ValidityState getValidityState() {
return new MyValidityState(myPackage, myDebug);
}
@Override
public Module getModule() {
return myModule;
}
@Override
public boolean isTestSource() {
return false;
}
}
private static class MyValidityState implements ValidityState {
private final String myPackage;
private boolean myDebug;
private MyValidityState(DataInput in) throws IOException {
myPackage = in.readUTF();
myDebug = in.readBoolean();
}
private MyValidityState(@NotNull String aPackage, boolean debug) {
myPackage = aPackage;
myDebug = debug;
}
@Override
public boolean equalsTo(ValidityState otherState) {
if (!(otherState instanceof MyValidityState)) {
return false;
}
final MyValidityState otherState1 = (MyValidityState)otherState;
return otherState1.myPackage.equals(myPackage) && otherState1.myDebug == myDebug;
}
@Override
public void save(DataOutput out) throws IOException {
out.writeUTF(myPackage);
out.writeBoolean(myDebug);
}
}
}
@@ -654,6 +654,8 @@ public class AndroidCompileUtil {
final Module module = facet.getModule();
final GlobalSearchScope moduleScope = facet.getModule().getModuleScope();
initializeGenSourceRoot(module, AndroidRootUtil.getBuildconfigGenSourceRootPath(facet), true, true);
initializeGenSourceRoot(module, AndroidRootUtil.getRenderscriptGenSourceRootPath(facet),
FileTypeIndex.getFiles(AndroidRenderscriptFileType.INSTANCE, moduleScope).size() > 0, true);
@@ -900,4 +902,20 @@ public class AndroidCompileUtil {
}
return null;
}
@NotNull
public static String[] getLibPackages(@NotNull Module module, @NotNull String packageName) {
final Set<String> packageSet = new HashSet<String>();
packageSet.add(packageName);
final List<String> result = new ArrayList<String>();
for (String libPackage : AndroidUtils.getDepLibsPackages(module)) {
if (packageSet.add(libPackage)) {
result.add(libPackage);
}
}
return ArrayUtil.toStringArray(result);
}
}
@@ -190,6 +190,11 @@ public class AndroidPrecompileTask implements CompileTask {
sourceRootSet.remove(rsGenRoot);
}
final VirtualFile buildconfigGenDir = AndroidRootUtil.getBuildconfigGenDir(facet);
if (buildconfigGenDir != null) {
sourceRootSet.remove(buildconfigGenDir);
}
final ExcludeEntryDescription[] descriptions = configuration.getExcludeEntryDescriptions();
configuration.removeAllExcludeEntryDescriptions();
@@ -459,6 +459,7 @@ public class AndroidFacet extends Facet<AndroidFacetConfiguration> {
AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AIDL);
}
AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.RENDERSCRIPT);
AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.BUILDCONFIG);
activateSourceAutogenerating();
}
@@ -39,6 +39,9 @@ import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.jetbrains.android.util.AndroidUtils.findSourceRoot;
@@ -144,59 +147,61 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
return;
}
final AndroidAutogeneratorMode autogenerationMode =
ApplicationManager.getApplication().runReadAction(new Computable<AndroidAutogeneratorMode>() {
final List<AndroidAutogeneratorMode> autogenerationModes =
ApplicationManager.getApplication().runReadAction(new Computable<List<AndroidAutogeneratorMode>>() {
@Nullable
public AndroidAutogeneratorMode compute() {
return computeCompilerToRunAndInvalidateLocalAttributesMap();
public List<AndroidAutogeneratorMode> compute() {
return computeCompilersToRunAndInvalidateLocalAttributesMap();
}
});
if (autogenerationMode == null) {
if (autogenerationModes.isEmpty()) {
return;
}
if (autogenerationMode == AndroidAutogeneratorMode.AAPT &&
AndroidRootUtil.getManifestFile(myFacet) != myEvent.getFile()) {
for (AndroidAutogeneratorMode autogenerationMode : autogenerationModes) {
if (autogenerationMode == AndroidAutogeneratorMode.AAPT &&
AndroidRootUtil.getManifestFile(myFacet) != myEvent.getFile()) {
final HashSet<ResourceEntry> resourceSet = new HashSet<ResourceEntry>();
final HashSet<ResourceEntry> resourceSet = new HashSet<ResourceEntry>();
DumbService.getInstance(myFacet.getModule().getProject()).waitForSmartMode();
DumbService.getInstance(myFacet.getModule().getProject()).waitForSmartMode();
AndroidCompileUtil.collectAllResources(myFacet, resourceSet);
AndroidCompileUtil.collectAllResources(myFacet, resourceSet);
synchronized (RESOURCES_SET_LOCK) {
if (resourceSet.equals(myResourceSet) &&
!myFacet.areSourcesGeneratedWithErrors(AndroidAutogeneratorMode.AAPT)) {
return;
synchronized (RESOURCES_SET_LOCK) {
if (resourceSet.equals(myResourceSet) &&
!myFacet.areSourcesGeneratedWithErrors(AndroidAutogeneratorMode.AAPT)) {
return;
}
myResourceSet = resourceSet;
}
myResourceSet = resourceSet;
}
AndroidCompileUtil.generate(myFacet.getModule(), autogenerationMode, true);
}
AndroidCompileUtil.generate(myFacet.getModule(), autogenerationMode, true);
}
@Nullable
private AndroidAutogeneratorMode computeCompilerToRunAndInvalidateLocalAttributesMap() {
@NotNull
private List<AndroidAutogeneratorMode> computeCompilersToRunAndInvalidateLocalAttributesMap() {
if (myFacet.isDisposed()) {
return null;
return Collections.emptyList();
}
final Module myModule = myFacet.getModule();
final Project project = myModule.getProject();
if (project.isDisposed()) {
return null;
return Collections.emptyList();
}
final VirtualFile file = myEvent.getFile();
final Module module = ModuleUtil.findModuleForFile(file, project);
if (module != myModule) {
return null;
return Collections.emptyList();
}
VirtualFile parent = myEvent.getParent();
if (parent == null) {
return null;
return Collections.emptyList();
}
final VirtualFile gp = parent.getParent();
@@ -207,10 +212,13 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
ResourceFolderType.VALUES.getName().equals(AndroidCommonUtils.getResourceTypeByDirName(parent.getName()))) {
myFacet.getLocalResourceManager().invalidateAttributeDefinitions();
}
final VirtualFile manifestFile = AndroidRootUtil.getManifestFile(myFacet);
final List<AndroidAutogeneratorMode> modes = new ArrayList<AndroidAutogeneratorMode>();
if (AndroidAptCompiler.isToCompileModule(module, myFacet.getConfiguration()) &&
(myFacet.getConfiguration().REGENERATE_R_JAVA && (gp == resourceDir ||
AndroidRootUtil.getManifestFile(myFacet) == file))) {
manifestFile == file))) {
final Manifest manifest = myFacet.getManifest();
final String aPackage = manifest != null ? manifest.getPackage().getValue() : null;
@@ -219,23 +227,27 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
AndroidCompileUtil.removeDuplicatingClasses(myModule, myCachedPackage, AndroidUtils.R_CLASS_NAME, null, aptGenDirPath);
}
myCachedPackage = aPackage;
return AndroidAutogeneratorMode.AAPT;
modes.add(AndroidAutogeneratorMode.AAPT);
}
if (myFacet.getConfiguration().REGENERATE_JAVA_BY_AIDL && file.getFileType() == AndroidIdlFileType.ourFileType) {
VirtualFile sourceRoot = findSourceRoot(myModule, file);
if (sourceRoot != null && AndroidRootUtil.getAidlGenDir(myFacet) != sourceRoot) {
return AndroidAutogeneratorMode.AIDL;
modes.add(AndroidAutogeneratorMode.AIDL);
}
}
if (file.getFileType() == AndroidRenderscriptFileType.INSTANCE) {
final VirtualFile sourceRoot = findSourceRoot(myModule, file);
if (sourceRoot != null && AndroidRootUtil.getRenderscriptGenDir(myFacet) != sourceRoot) {
return AndroidAutogeneratorMode.RENDERSCRIPT;
modes.add(AndroidAutogeneratorMode.RENDERSCRIPT);
}
}
return null;
if (manifestFile == file) {
modes.add(AndroidAutogeneratorMode.BUILDCONFIG);
}
return modes;
}
@Override
@@ -178,6 +178,12 @@ public class AndroidRootUtil {
return path != null ? LocalFileSystem.getInstance().findFileByPath(path) : null;
}
@Nullable
public static VirtualFile getBuildconfigGenDir(@NotNull AndroidFacet facet) {
final String path = getBuildconfigGenSourceRootPath(facet);
return path != null ? LocalFileSystem.getInstance().findFileByPath(path) : null;
}
// works even if there is no Android facet in a module
@Nullable
@@ -355,14 +361,25 @@ public class AndroidRootUtil {
@Nullable
public static String getRenderscriptGenSourceRootPath(@NotNull AndroidFacet facet) {
// todo: return correct path for mavenized module
// todo: return correct path for mavenized module when it'll be supported
return getDefaultGenSourceRoot(facet);
}
@Nullable
public static String getBuildconfigGenSourceRootPath(@NotNull AndroidFacet facet) {
// todo: return correct path for mavenized module when it'll be supported
return getDefaultGenSourceRoot(facet);
}
@Nullable
private static String getDefaultGenSourceRoot(AndroidFacet facet) {
final VirtualFile mainContentRoot = getMainContentRoot(facet);
final String moduleDirPath = mainContentRoot != null ? mainContentRoot.getPath() : null;
return moduleDirPath != null
? moduleDirPath + '/' + SdkConstants.FD_GEN_SOURCES
: null;
}
@Nullable
public static VirtualFile getMainContentRoot(@NotNull AndroidFacet facet) {
final Module module = facet.getModule();