mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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) {}
|
||||
}
|
||||
}
|
||||
+26
@@ -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>);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -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(); }
|
||||
|
||||
}
|
||||
|
||||
+28
-58
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+193
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user