Extract AnalyzerFacade interface. Extract AnalyzerFacadeWithCache decorator for AnalyzerFacade.

This commit is contained in:
Pavel V. Talanov
2012-04-04 17:20:27 +04:00
parent 766b4dc975
commit 1ad12b29fa
12 changed files with 745 additions and 493 deletions
@@ -18,23 +18,16 @@ package org.jetbrains.jet.lang.resolve.java;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.Function; import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.analyzer.AnalyzerFacade;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm; import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.BindingTraceContext;
@@ -48,106 +41,20 @@ import java.util.Collections;
/** /**
* @author abreslav * @author abreslav
*/ */
public class AnalyzerFacadeForJVM { public enum AnalyzerFacadeForJVM implements AnalyzerFacade {
private static final Logger LOG = Logger.getInstance("org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM"); INSTANCE;
public static final Function<JetFile, Collection<JetFile>> SINGLE_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetFile>>() {
@Override
public Collection<JetFile> fun(JetFile file) {
return Collections.singleton(file);
}
};
private final static Key<CachedValue<AnalyzeExhaust>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
private static final Object lock = new Object();
private AnalyzerFacadeForJVM() { private AnalyzerFacadeForJVM() {
} }
/** @Override
* Analyze project with string cache for given file. Given file will be fully analyzed. @NotNull
* public AnalyzeExhaust analyzeFiles(@NotNull Project project,
* @param file @NotNull Collection<JetFile> files,
* @param declarationProvider @NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
* @return @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
*/ return analyzeFilesWithJavaIntegration(project, files, filesToAnalyzeCompletely, flowDataTraceFactory, CompilerSpecialMode.REGULAR);
public static AnalyzeExhaust analyzeFileWithCache(@NotNull final JetFile file,
@NotNull final Function<JetFile, Collection<JetFile>> declarationProvider) {
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
synchronized (lock) {
CachedValue<AnalyzeExhaust> bindingContextCachedValue = file.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue =
CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
try {
AnalyzeExhaust bindingContext = analyzeFilesWithJavaIntegration(
file.getProject(),
declarationProvider.fun(file),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY,
CompilerSpecialMode.REGULAR);
return new Result<AnalyzeExhaust>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
DiagnosticUtils.throwIfRunningOnServer(e);
LOG.error(e);
BindingTraceContext bindingTraceContext = new BindingTraceContext();
bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e));
AnalyzeExhaust analyzeExhaust = new AnalyzeExhaust(bindingTraceContext.getBindingContext(), null);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
}
}, false);
file.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
/**
* Analyze project with string cache for the whole project. All given files will be analyzed only for descriptors.
*/
public static AnalyzeExhaust analyzeProjectWithCache(@NotNull final Project project,
@NotNull final Collection<JetFile> files) {
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
synchronized (lock) {
CachedValue<AnalyzeExhaust> bindingContextCachedValue = project.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue =
CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
try {
AnalyzeExhaust analyzeExhaust = analyzeFilesWithJavaIntegration(
project,
files,
Predicates.<PsiFile>alwaysFalse(),
JetControlFlowDataTraceFactory.EMPTY,
CompilerSpecialMode.REGULAR);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
DiagnosticUtils.throwIfRunningOnServer(e);
LOG.error(e);
BindingTraceContext bindingTraceContext = new BindingTraceContext();
AnalyzeExhaust analyzeExhaust = new AnalyzeExhaust(bindingTraceContext.getBindingContext(), null);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
}
}, false);
project.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
} }
public static AnalyzeExhaust analyzeOneFileWithJavaIntegrationAndCheckForErrors( public static AnalyzeExhaust analyzeOneFileWithJavaIntegrationAndCheckForErrors(
@@ -196,4 +103,15 @@ public class AnalyzerFacadeForJVM {
return analyzeFilesWithJavaIntegration(project, files, Predicates.<PsiFile>alwaysFalse(), return analyzeFilesWithJavaIntegration(project, files, Predicates.<PsiFile>alwaysFalse(),
JetControlFlowDataTraceFactory.EMPTY, CompilerSpecialMode.REGULAR); JetControlFlowDataTraceFactory.EMPTY, CompilerSpecialMode.REGULAR);
} }
@NotNull
public static AnalyzeExhaust analyzeFileWithCache(@NotNull final JetFile file,
@NotNull final Function<JetFile, Collection<JetFile>> declarationProvider) {
return AnalyzerFacadeWithCache.getInstance(INSTANCE).analyzeFileWithCache(file, declarationProvider);
}
@NotNull
public static AnalyzeExhaust analyzeProjectWithCache(@NotNull final Project project, @NotNull final Collection<JetFile> files) {
return AnalyzerFacadeWithCache.getInstance(INSTANCE).analyzeProjectWithCache(project, files);
}
} }
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2012 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.jet.analyzer;
import com.google.common.base.Predicate;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetFile;
import java.util.Collection;
/**
* @author Pavel Talanov
*/
public interface AnalyzerFacade {
@NotNull
AnalyzeExhaust analyzeFiles(@NotNull Project project,
@NotNull Collection<JetFile> files,
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory);
}
@@ -0,0 +1,171 @@
/*
* Copyright 2010-2012 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.jet.analyzer;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import java.util.Collection;
import java.util.Collections;
/**
* @author Pavel Talanov
*/
public class AnalyzerFacadeWithCache implements AnalyzerFacade {
private static final Logger LOG = Logger.getInstance("org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache");
private final static Key<CachedValue<AnalyzeExhaust>> ANALYZE_EXHAUST = Key.create("ANALYZE_EXHAUST");
private static final Object lock = new Object();
public static final Function<JetFile, Collection<JetFile>> SINGLE_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetFile>>() {
@Override
public Collection<JetFile> fun(JetFile file) {
return Collections.singleton(file);
}
};
public static AnalyzerFacadeWithCache getInstance(@NotNull AnalyzerFacade facade) {
return new AnalyzerFacadeWithCache(facade);
}
@NotNull
private final AnalyzerFacade facade;
private AnalyzerFacadeWithCache(@NotNull AnalyzerFacade facade) {
this.facade = facade;
}
/**
* Analyze project with string cache for given file. Given file will be fully analyzed.
*
* @param file
* @param declarationProvider
* @return
*/
@NotNull
public AnalyzeExhaust analyzeFileWithCache(@NotNull final JetFile file,
@NotNull final Function<JetFile, Collection<JetFile>> declarationProvider) {
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
synchronized (lock) {
CachedValue<AnalyzeExhaust> bindingContextCachedValue = file.getUserData(ANALYZE_EXHAUST);
if (bindingContextCachedValue == null) {
bindingContextCachedValue =
CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
try {
AnalyzeExhaust exhaust = facade.analyzeFiles(file.getProject(),
declarationProvider.fun(file),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<AnalyzeExhaust>(exhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
handleError(e);
return emptyExhaustWithDiagnosticOnFile(e);
}
}
@NotNull
private Result<AnalyzeExhaust> emptyExhaustWithDiagnosticOnFile(Throwable e) {
BindingTraceContext bindingTraceContext = new BindingTraceContext();
bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e));
AnalyzeExhaust analyzeExhaust = new AnalyzeExhaust(bindingTraceContext.getBindingContext(), null);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
file.putUserData(ANALYZE_EXHAUST, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
private static void handleError(@NotNull Throwable e) {
DiagnosticUtils.throwIfRunningOnServer(e);
LOG.error(e);
}
/**
* Analyze project with string cache for the whole project. All given files will be analyzed only for descriptors.
*/
@NotNull
public AnalyzeExhaust analyzeProjectWithCache(@NotNull final Project project, @NotNull final Collection<JetFile> files) {
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
synchronized (lock) {
CachedValue<AnalyzeExhaust> bindingContextCachedValue = project.getUserData(ANALYZE_EXHAUST);
if (bindingContextCachedValue == null) {
bindingContextCachedValue =
CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
try {
AnalyzeExhaust analyzeExhaust = facade.analyzeFiles(project,
files,
Predicates.<PsiFile>alwaysFalse(),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
handleError(e);
return emptyExhaust();
}
}
@NotNull
private Result<AnalyzeExhaust> emptyExhaust() {
BindingTraceContext bindingTraceContext = new BindingTraceContext();
AnalyzeExhaust analyzeExhaust = new AnalyzeExhaust(bindingTraceContext.getBindingContext(), null);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
project.putUserData(ANALYZE_EXHAUST, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
@NotNull
@Override
public AnalyzeExhaust analyzeFiles(@NotNull Project project,
@NotNull Collection<JetFile> files,
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
return facade.analyzeFiles(project, files, filesToAnalyzeCompletely, flowDataTraceFactory);
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.jet.types;
import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.JetLiteFixture;
import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.di.InjectorForTests; import org.jetbrains.jet.di.InjectorForTests;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -63,7 +64,7 @@ public class JetDefaultModalityModifiersTest extends JetLiteFixture {
JetDeclaration aClass = declarations.get(0); JetDeclaration aClass = declarations.get(0);
assert aClass instanceof JetClass; assert aClass instanceof JetClass;
AnalyzeExhaust bindingContext = AnalyzeExhaust bindingContext =
AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER); AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER);
DeclarationDescriptor classDescriptor = DeclarationDescriptor classDescriptor =
bindingContext.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, aClass); bindingContext.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, aClass);
WritableScopeImpl scope = new WritableScopeImpl(libraryScope, root, RedeclarationHandler.DO_NOTHING); WritableScopeImpl scope = new WritableScopeImpl(libraryScope, root, RedeclarationHandler.DO_NOTHING);
@@ -32,6 +32,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import jet.Tuple2; import jet.Tuple2;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -57,18 +58,18 @@ public class JetSourceNavigationHelper {
} }
@Nullable @Nullable
private static<D extends ClassOrNamespaceDescriptor> Tuple2<BindingContext, D> private static <D extends ClassOrNamespaceDescriptor> Tuple2<BindingContext, D>
getBindingContextAndClassOrNamespaceDescriptor(@NotNull WritableSlice<FqName, D> slice, getBindingContextAndClassOrNamespaceDescriptor(@NotNull WritableSlice<FqName, D> slice,
@NotNull JetDeclaration declaration, @NotNull JetDeclaration declaration,
@Nullable FqName fqName) { @Nullable FqName fqName) {
if (fqName == null || DumbService.isDumb(declaration.getProject())) { if (fqName == null || DumbService.isDumb(declaration.getProject())) {
return null; return null;
} }
final List<JetFile> libraryFiles = findAllSourceFilesWhichContainIdentifier(declaration); final List<JetFile> libraryFiles = findAllSourceFilesWhichContainIdentifier(declaration);
for (JetFile libraryFile : libraryFiles) { for (JetFile libraryFile : libraryFiles) {
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache(libraryFile, BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache(libraryFile,
AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
D descriptor = bindingContext.get(slice, fqName); D descriptor = bindingContext.get(slice, fqName);
if (descriptor != null) { if (descriptor != null) {
return new Tuple2<BindingContext, D>(bindingContext, descriptor); return new Tuple2<BindingContext, D>(bindingContext, descriptor);
@@ -79,22 +80,25 @@ public class JetSourceNavigationHelper {
@Nullable @Nullable
private static Tuple2<BindingContext, ClassDescriptor> getBindingContextAndClassDescriptor(@NotNull JetClass decompiledClass) { private static Tuple2<BindingContext, ClassDescriptor> getBindingContextAndClassDescriptor(@NotNull JetClass decompiledClass) {
return getBindingContextAndClassOrNamespaceDescriptor(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, decompiledClass, JetPsiUtil.getFQName(decompiledClass)); return getBindingContextAndClassOrNamespaceDescriptor(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, decompiledClass,
JetPsiUtil.getFQName(decompiledClass));
} }
@Nullable @Nullable
private static Tuple2<BindingContext, NamespaceDescriptor> getBindingContextAndNamespaceDescriptor(@NotNull JetDeclaration declaration) { private static Tuple2<BindingContext, NamespaceDescriptor> getBindingContextAndNamespaceDescriptor(@NotNull JetDeclaration declaration) {
JetFile file = (JetFile) declaration.getContainingFile(); JetFile file = (JetFile)declaration.getContainingFile();
return getBindingContextAndClassOrNamespaceDescriptor(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, declaration, JetPsiUtil.getFQName(file)); return getBindingContextAndClassOrNamespaceDescriptor(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, declaration,
JetPsiUtil.getFQName(file));
} }
@Nullable @Nullable
public static JetClass getSourceClass(@NotNull JetClass decompiledClass) { public static JetClass getSourceClass(@NotNull JetClass decompiledClass) {
Tuple2<BindingContext, ClassDescriptor> bindingContextAndClassDescriptor = getBindingContextAndClassDescriptor(decompiledClass); Tuple2<BindingContext, ClassDescriptor> bindingContextAndClassDescriptor = getBindingContextAndClassDescriptor(decompiledClass);
if (bindingContextAndClassDescriptor == null) return null; if (bindingContextAndClassDescriptor == null) return null;
PsiElement declaration = bindingContextAndClassDescriptor._1.get(BindingContext.DESCRIPTOR_TO_DECLARATION, bindingContextAndClassDescriptor._2); PsiElement declaration =
bindingContextAndClassDescriptor._1.get(BindingContext.DESCRIPTOR_TO_DECLARATION, bindingContextAndClassDescriptor._2);
assert declaration instanceof JetClass; assert declaration instanceof JetClass;
return (JetClass) declaration; return (JetClass)declaration;
} }
@NotNull @NotNull
@@ -119,12 +123,13 @@ public class JetSourceNavigationHelper {
Project project = jetDeclaration.getProject(); Project project = jetDeclaration.getProject();
CacheManager cacheManager = CacheManager.SERVICE.getInstance(project); CacheManager cacheManager = CacheManager.SERVICE.getInstance(project);
PsiFile[] filesWithWord = cacheManager.getFilesWithWord(name, PsiFile[] filesWithWord = cacheManager.getFilesWithWord(name,
UsageSearchContext.IN_CODE, createLibrarySourcesScopeForFile(libraryFile, project), UsageSearchContext.IN_CODE,
createLibrarySourcesScopeForFile(libraryFile, project),
true); true);
List<JetFile> jetFiles = new ArrayList<JetFile>(); List<JetFile> jetFiles = new ArrayList<JetFile>();
for (PsiFile psiFile : filesWithWord) { for (PsiFile psiFile : filesWithWord) {
if (psiFile instanceof JetFile) { if (psiFile instanceof JetFile) {
jetFiles.add((JetFile) psiFile); jetFiles.add((JetFile)psiFile);
} }
} }
return jetFiles; return jetFiles;
@@ -132,9 +137,9 @@ public class JetSourceNavigationHelper {
@Nullable @Nullable
private static <Decl extends JetDeclaration, Descr extends CallableDescriptor> JetDeclaration private static <Decl extends JetDeclaration, Descr extends CallableDescriptor> JetDeclaration
getSourcePropertyOrFunction(final @NotNull Decl decompiledDeclaration, getSourcePropertyOrFunction(final @NotNull Decl decompiledDeclaration,
JetTypeReference receiverType, JetTypeReference receiverType,
Matcher<Decl, Descr> matcher) { Matcher<Decl, Descr> matcher) {
String entityName = decompiledDeclaration.getName(); String entityName = decompiledDeclaration.getName();
if (entityName == null) { if (entityName == null) {
return null; return null;
@@ -142,7 +147,8 @@ public class JetSourceNavigationHelper {
PsiElement declarationContainer = decompiledDeclaration.getParent(); PsiElement declarationContainer = decompiledDeclaration.getParent();
if (declarationContainer instanceof JetFile) { if (declarationContainer instanceof JetFile) {
Tuple2<BindingContext, NamespaceDescriptor> bindingContextAndNamespaceDescriptor = getBindingContextAndNamespaceDescriptor(decompiledDeclaration); Tuple2<BindingContext, NamespaceDescriptor> bindingContextAndNamespaceDescriptor =
getBindingContextAndNamespaceDescriptor(decompiledDeclaration);
if (bindingContextAndNamespaceDescriptor == null) return null; if (bindingContextAndNamespaceDescriptor == null) return null;
BindingContext bindingContext = bindingContextAndNamespaceDescriptor._1; BindingContext bindingContext = bindingContextAndNamespaceDescriptor._1;
NamespaceDescriptor namespaceDescriptor = bindingContextAndNamespaceDescriptor._2; NamespaceDescriptor namespaceDescriptor = bindingContextAndNamespaceDescriptor._2;
@@ -151,11 +157,12 @@ public class JetSourceNavigationHelper {
for (Descr candidate : matcher.getCandidatesFromScope(namespaceDescriptor.getMemberScope(), entityName)) { for (Descr candidate : matcher.getCandidatesFromScope(namespaceDescriptor.getMemberScope(), entityName)) {
if (candidate.getReceiverParameter() == ReceiverDescriptor.NO_RECEIVER) { if (candidate.getReceiverParameter() == ReceiverDescriptor.NO_RECEIVER) {
if (matcher.areSame(decompiledDeclaration, candidate)) { if (matcher.areSame(decompiledDeclaration, candidate)) {
return (JetDeclaration) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, candidate); return (JetDeclaration)bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, candidate);
} }
} }
} }
} else { }
else {
// extension property // extension property
String expectedTypeString = receiverType.getText(); String expectedTypeString = receiverType.getText();
for (Descr candidate : matcher.getCandidatesFromScope(namespaceDescriptor.getMemberScope(), entityName)) { for (Descr candidate : matcher.getCandidatesFromScope(namespaceDescriptor.getMemberScope(), entityName)) {
@@ -163,7 +170,7 @@ public class JetSourceNavigationHelper {
String thisReceiverType = DescriptorRenderer.TEXT.renderType(candidate.getReceiverParameter().getType()); String thisReceiverType = DescriptorRenderer.TEXT.renderType(candidate.getReceiverParameter().getType());
if (expectedTypeString.equals(thisReceiverType)) { if (expectedTypeString.equals(thisReceiverType)) {
if (matcher.areSame(decompiledDeclaration, candidate)) { if (matcher.areSame(decompiledDeclaration, candidate)) {
return (JetDeclaration) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, candidate); return (JetDeclaration)bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, candidate);
} }
} }
} }
@@ -194,7 +201,7 @@ public class JetSourceNavigationHelper {
ClassDescriptor expectedContainer = isClassObject ? classDescriptor.getClassObjectDescriptor() : classDescriptor; ClassDescriptor expectedContainer = isClassObject ? classDescriptor.getClassObjectDescriptor() : classDescriptor;
for (Descr candidate : matcher.getCandidatesFromScope(memberScope, entityName)) { for (Descr candidate : matcher.getCandidatesFromScope(memberScope, entityName)) {
if (candidate.getContainingDeclaration() == expectedContainer) { if (candidate.getContainingDeclaration() == expectedContainer) {
JetDeclaration property = (JetDeclaration) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, candidate); JetDeclaration property = (JetDeclaration)bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, candidate);
if (property != null) { if (property != null) {
return property; return property;
} }
@@ -207,51 +214,54 @@ public class JetSourceNavigationHelper {
@Nullable @Nullable
public static JetDeclaration getSourceProperty(final @NotNull JetProperty decompiledProperty) { public static JetDeclaration getSourceProperty(final @NotNull JetProperty decompiledProperty) {
return getSourcePropertyOrFunction(decompiledProperty, decompiledProperty.getReceiverTypeRef(), new Matcher<JetProperty, VariableDescriptor>() { return getSourcePropertyOrFunction(decompiledProperty, decompiledProperty.getReceiverTypeRef(),
@Override new Matcher<JetProperty, VariableDescriptor>() {
public boolean areSame(JetProperty declaration, VariableDescriptor descriptor) { @Override
return true; public boolean areSame(JetProperty declaration, VariableDescriptor descriptor) {
} return true;
}
@Override @Override
public Set<VariableDescriptor> getCandidatesFromScope(JetScope scope, String name) { public Set<VariableDescriptor> getCandidatesFromScope(JetScope scope, String name) {
return scope.getProperties(name); return scope.getProperties(name);
} }
}); });
} }
@Nullable @Nullable
public static JetDeclaration getSourceFunction(final @NotNull JetFunction decompiledFunction) { public static JetDeclaration getSourceFunction(final @NotNull JetFunction decompiledFunction) {
return getSourcePropertyOrFunction(decompiledFunction, decompiledFunction.getReceiverTypeRef(), new Matcher<JetFunction, FunctionDescriptor>() { return getSourcePropertyOrFunction(decompiledFunction, decompiledFunction.getReceiverTypeRef(),
@Override new Matcher<JetFunction, FunctionDescriptor>() {
public boolean areSame(JetFunction declaration, FunctionDescriptor descriptor) { @Override
List<JetParameter> declarationParameters = declaration.getValueParameters(); public boolean areSame(JetFunction declaration, FunctionDescriptor descriptor) {
List<ValueParameterDescriptor> descriptorParameters = descriptor.getValueParameters(); List<JetParameter> declarationParameters = declaration.getValueParameters();
if (descriptorParameters.size() != declarationParameters.size()) { List<ValueParameterDescriptor> descriptorParameters = descriptor.getValueParameters();
return false; if (descriptorParameters.size() != declarationParameters.size()) {
} return false;
}
for (int i = 0; i < descriptorParameters.size(); i++) { for (int i = 0; i < descriptorParameters.size(); i++) {
ValueParameterDescriptor descriptorParameter = descriptorParameters.get(i); ValueParameterDescriptor descriptorParameter = descriptorParameters.get(i);
JetParameter declarationParameter = declarationParameters.get(i); JetParameter declarationParameter = declarationParameters.get(i);
JetTypeReference typeReference = declarationParameter.getTypeReference(); JetTypeReference typeReference = declarationParameter.getTypeReference();
if (typeReference == null) { if (typeReference == null) {
return false; return false;
} }
String declarationTypeText = typeReference.getText(); String declarationTypeText = typeReference.getText();
String descriptorParameterText = DescriptorRenderer.TEXT.renderType(descriptorParameter.getType()); String descriptorParameterText =
if (!declarationTypeText.equals(descriptorParameterText)) { DescriptorRenderer.TEXT.renderType(descriptorParameter.getType());
return false; if (!declarationTypeText.equals(descriptorParameterText)) {
} return false;
} }
return true; }
} return true;
}
@Override @Override
public Set<FunctionDescriptor> getCandidatesFromScope(JetScope scope, String name) { public Set<FunctionDescriptor> getCandidatesFromScope(JetScope scope, String name) {
return scope.getFunctions(name); return scope.getFunctions(name);
} }
}); });
} }
private interface Matcher<Decl extends JetDeclaration, Descr extends CallableDescriptor> { private interface Matcher<Decl extends JetDeclaration, Descr extends CallableDescriptor> {
@@ -26,6 +26,7 @@ import com.intellij.psi.PsiReference;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.compiler.TipsManager; import org.jetbrains.jet.compiler.TipsManager;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -47,7 +48,7 @@ import java.util.List;
* Date: 17.01.12 * Date: 17.01.12
*/ */
public class JetFunctionParameterInfoHandler implements public class JetFunctionParameterInfoHandler implements
ParameterInfoHandlerWithTabActionSupport<JetValueArgumentList, Object, JetValueArgument> { ParameterInfoHandlerWithTabActionSupport<JetValueArgumentList, Object, JetValueArgument> {
public final static Color GREEN_BACKGROUND = new Color(231, 254, 234); public final static Color GREEN_BACKGROUND = new Color(231, 254, 234);
@NotNull @NotNull
@@ -72,7 +73,7 @@ public class JetFunctionParameterInfoHandler implements
@NotNull @NotNull
@Override @Override
public Set<Class> getArgumentListAllowedParentClasses() { public Set<Class> getArgumentListAllowedParentClasses() {
return Collections.singleton((Class) JetCallElement.class); return Collections.singleton((Class)JetCallElement.class);
} }
@NotNull @NotNull
@@ -139,7 +140,7 @@ public class JetFunctionParameterInfoHandler implements
public boolean tracksParameterIndex() { public boolean tracksParameterIndex() {
return true; return true;
} }
private static String renderParameter(ValueParameterDescriptor descriptor, boolean named, BindingContext bindingContext) { private static String renderParameter(ValueParameterDescriptor descriptor, boolean named, BindingContext bindingContext) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
if (named) builder.append("["); if (named) builder.append("[");
@@ -147,21 +148,27 @@ public class JetFunctionParameterInfoHandler implements
builder.append("vararg "); builder.append("vararg ");
} }
builder.append(descriptor.getName()).append(": "). builder.append(descriptor.getName()).append(": ").
append(DescriptorRenderer.TEXT.renderType(getActualParameterType(descriptor))); append(DescriptorRenderer.TEXT.renderType(getActualParameterType(descriptor)));
if (descriptor.hasDefaultValue()) { if (descriptor.hasDefaultValue()) {
PsiElement element = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); PsiElement element = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
String defaultExpression = "?"; String defaultExpression = "?";
if (element instanceof JetParameter) { if (element instanceof JetParameter) {
JetParameter parameter = (JetParameter) element; JetParameter parameter = (JetParameter)element;
JetExpression defaultValue = parameter.getDefaultValue(); JetExpression defaultValue = parameter.getDefaultValue();
if (defaultValue != null) { if (defaultValue != null) {
if (defaultValue instanceof JetConstantExpression) { if (defaultValue instanceof JetConstantExpression) {
JetConstantExpression constantExpression = (JetConstantExpression) defaultValue; JetConstantExpression constantExpression = (JetConstantExpression)defaultValue;
defaultExpression = constantExpression.getText(); defaultExpression = constantExpression.getText();
if (defaultExpression.length() > 10) { if (defaultExpression.length() > 10) {
if (defaultExpression.startsWith("\"")) defaultExpression = "\"...\""; if (defaultExpression.startsWith("\"")) {
else if (defaultExpression.startsWith("\'")) defaultExpression = "\'...\'"; defaultExpression = "\"...\"";
else defaultExpression = defaultExpression.substring(0, 7) + "..."; }
else if (defaultExpression.startsWith("\'")) {
defaultExpression = "\'...\'";
}
else {
defaultExpression = defaultExpression.substring(0, 7) + "...";
}
} }
} }
} }
@@ -171,7 +178,7 @@ public class JetFunctionParameterInfoHandler implements
if (named) builder.append("]"); if (named) builder.append("]");
return builder.toString(); return builder.toString();
} }
private static JetType getActualParameterType(ValueParameterDescriptor descriptor) { private static JetType getActualParameterType(ValueParameterDescriptor descriptor) {
JetType paramType = descriptor.getType(); JetType paramType = descriptor.getType();
if (descriptor.getVarargElementType() != null) paramType = descriptor.getVarargElementType(); if (descriptor.getVarargElementType() != null) paramType = descriptor.getVarargElementType();
@@ -186,13 +193,13 @@ public class JetFunctionParameterInfoHandler implements
} }
PsiElement parameterOwner = context.getParameterOwner(); PsiElement parameterOwner = context.getParameterOwner();
if (parameterOwner instanceof JetValueArgumentList) { if (parameterOwner instanceof JetValueArgumentList) {
JetValueArgumentList argumentList = (JetValueArgumentList) parameterOwner; JetValueArgumentList argumentList = (JetValueArgumentList)parameterOwner;
if (descriptor instanceof FunctionDescriptor) { if (descriptor instanceof FunctionDescriptor) {
JetFile file = (JetFile) argumentList.getContainingFile(); JetFile file = (JetFile)argumentList.getContainingFile();
BindingContext bindingContext = BindingContext bindingContext =
AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; FunctionDescriptor functionDescriptor = (FunctionDescriptor)descriptor;
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
List<JetValueArgument> valueArguments = argumentList.getArguments(); List<JetValueArgument> valueArguments = argumentList.getArguments();
@@ -204,27 +211,28 @@ public class JetFunctionParameterInfoHandler implements
Color color = context.getDefaultParameterColor(); Color color = context.getDefaultParameterColor();
PsiElement parent = argumentList.getParent(); PsiElement parent = argumentList.getParent();
if (parent instanceof JetCallElement) { if (parent instanceof JetCallElement) {
JetCallElement callExpression = (JetCallElement) parent; JetCallElement callExpression = (JetCallElement)parent;
JetExpression calleeExpression = callExpression.getCalleeExpression(); JetExpression calleeExpression = callExpression.getCalleeExpression();
JetSimpleNameExpression refExpression = null; JetSimpleNameExpression refExpression = null;
if (calleeExpression instanceof JetSimpleNameExpression) { if (calleeExpression instanceof JetSimpleNameExpression) {
refExpression = (JetSimpleNameExpression) calleeExpression; refExpression = (JetSimpleNameExpression)calleeExpression;
} else if (calleeExpression instanceof JetConstructorCalleeExpression) { }
JetConstructorCalleeExpression constructorCalleeExpression = (JetConstructorCalleeExpression) calleeExpression; else if (calleeExpression instanceof JetConstructorCalleeExpression) {
JetConstructorCalleeExpression constructorCalleeExpression = (JetConstructorCalleeExpression)calleeExpression;
if (constructorCalleeExpression.getConstructorReferenceExpression() instanceof JetSimpleNameExpression) { if (constructorCalleeExpression.getConstructorReferenceExpression() instanceof JetSimpleNameExpression) {
refExpression = (JetSimpleNameExpression) constructorCalleeExpression.getConstructorReferenceExpression(); refExpression = (JetSimpleNameExpression)constructorCalleeExpression.getConstructorReferenceExpression();
} }
} }
if (refExpression != null) { if (refExpression != null) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, refExpression); DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, refExpression);
if (declarationDescriptor != null) { if (declarationDescriptor != null) {
if (declarationDescriptor == functionDescriptor) { if (declarationDescriptor == functionDescriptor) {
color = GREEN_BACKGROUND; color = GREEN_BACKGROUND;
} }
} }
} }
} }
boolean[] usedIndexes = new boolean[valueParameters.size()]; boolean[] usedIndexes = new boolean[valueParameters.size()];
boolean namedMode = false; boolean namedMode = false;
Arrays.fill(usedIndexes, false); Arrays.fill(usedIndexes, false);
@@ -236,35 +244,40 @@ public class JetFunctionParameterInfoHandler implements
if (valueParameters.size() == 0) builder.append(CodeInsightBundle.message("parameter.info.no.parameters")); if (valueParameters.size() == 0) builder.append(CodeInsightBundle.message("parameter.info.no.parameters"));
for (int i = 0; i < valueParameters.size(); ++i) { for (int i = 0; i < valueParameters.size(); ++i) {
if (i != 0) builder.append(", "); if (i != 0) builder.append(", ");
boolean highlightParameter = boolean highlightParameter =
i == currentParameterIndex || (!namedMode && i < currentParameterIndex && i == currentParameterIndex || (!namedMode && i < currentParameterIndex &&
valueParameters.get(valueParameters.size() - 1). valueParameters.get(valueParameters.size() - 1).
getVarargElementType() != null); getVarargElementType() != null);
if (highlightParameter) boldStartOffset = builder.length(); if (highlightParameter) boldStartOffset = builder.length();
if (!namedMode) { if (!namedMode) {
if (valueArguments.size() > i) { if (valueArguments.size() > i) {
JetValueArgument argument = valueArguments.get(i); JetValueArgument argument = valueArguments.get(i);
if (argument.isNamed()) { if (argument.isNamed()) {
namedMode = true; namedMode = true;
} else { }
else {
ValueParameterDescriptor param = valueParameters.get(i); ValueParameterDescriptor param = valueParameters.get(i);
builder.append(renderParameter(param, false, bindingContext)); builder.append(renderParameter(param, false, bindingContext));
if (i < currentParameterIndex) { if (i < currentParameterIndex) {
if (argument.getArgumentExpression() != null) { if (argument.getArgumentExpression() != null) {
//check type //check type
JetType paramType = getActualParameterType(param); JetType paramType = getActualParameterType(param);
JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression()); JetType exprType =
bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
if (exprType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) isGrey = true; if (exprType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) isGrey = true;
} }
else isGrey = true; else {
isGrey = true;
}
} }
usedIndexes[i] = true; usedIndexes[i] = true;
} }
} else { }
else {
ValueParameterDescriptor param = valueParameters.get(i); ValueParameterDescriptor param = valueParameters.get(i);
builder.append(renderParameter(param, false, bindingContext)); builder.append(renderParameter(param, false, bindingContext));
} }
} }
if (namedMode) { if (namedMode) {
boolean takeAnyArgument = true; boolean takeAnyArgument = true;
if (valueArguments.size() > i) { if (valueArguments.size() > i) {
@@ -282,20 +295,25 @@ public class JetFunctionParameterInfoHandler implements
if (argument.getArgumentExpression() != null) { if (argument.getArgumentExpression() != null) {
//check type //check type
JetType paramType = getActualParameterType(param); JetType paramType = getActualParameterType(param);
JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression()); JetType exprType =
if (exprType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) isGrey = true; bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
if (exprType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) {
isGrey = true;
}
}
else {
isGrey = true;
} }
else isGrey = true;
} }
break; break;
} }
} }
} }
} }
if (takeAnyArgument) { if (takeAnyArgument) {
if (i < currentParameterIndex) isGrey = true; if (i < currentParameterIndex) isGrey = true;
for (int j = 0; j < valueParameters.size(); ++j) { for (int j = 0; j < valueParameters.size(); ++j) {
ValueParameterDescriptor param = valueParameters.get(j); ValueParameterDescriptor param = valueParameters.get(j);
if (!usedIndexes[j]) { if (!usedIndexes[j]) {
@@ -308,10 +326,17 @@ public class JetFunctionParameterInfoHandler implements
} }
if (highlightParameter) boldEndOffset = builder.length(); if (highlightParameter) boldEndOffset = builder.length();
} }
if (builder.toString().isEmpty()) context.setUIComponentEnabled(false); if (builder.toString().isEmpty()) {
else context.setupUIComponentPresentation(builder.toString(), boldStartOffset, boldEndOffset, isGrey, context.setUIComponentEnabled(false);
isDeprecated, false, color); }
} else context.setUIComponentEnabled(false); else {
context.setupUIComponentPresentation(builder.toString(), boldStartOffset, boldEndOffset, isGrey,
isDeprecated, false, color);
}
}
else {
context.setUIComponentEnabled(false);
}
} }
} }
@@ -324,24 +349,28 @@ public class JetFunctionParameterInfoHandler implements
element = element.getParent(); element = element.getParent();
} }
if (element == null) return null; if (element == null) return null;
JetValueArgumentList argumentList = (JetValueArgumentList) element; JetValueArgumentList argumentList = (JetValueArgumentList)element;
JetCallElement callExpression; JetCallElement callExpression;
if (element.getParent() instanceof JetCallElement) { if (element.getParent() instanceof JetCallElement) {
callExpression = (JetCallElement) element.getParent(); callExpression = (JetCallElement)element.getParent();
} else return null; }
else {
return null;
}
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache( BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache(
(JetFile) file, (JetFile)file,
AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
JetExpression calleeExpression = callExpression.getCalleeExpression(); JetExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression == null) return null; if (calleeExpression == null) return null;
JetSimpleNameExpression refExpression = null; JetSimpleNameExpression refExpression = null;
if (calleeExpression instanceof JetSimpleNameExpression) { if (calleeExpression instanceof JetSimpleNameExpression) {
refExpression = (JetSimpleNameExpression) calleeExpression; refExpression = (JetSimpleNameExpression)calleeExpression;
} else if (calleeExpression instanceof JetConstructorCalleeExpression) { }
JetConstructorCalleeExpression constructorCalleeExpression = (JetConstructorCalleeExpression) calleeExpression; else if (calleeExpression instanceof JetConstructorCalleeExpression) {
JetConstructorCalleeExpression constructorCalleeExpression = (JetConstructorCalleeExpression)calleeExpression;
if (constructorCalleeExpression.getConstructorReferenceExpression() instanceof JetSimpleNameExpression) { if (constructorCalleeExpression.getConstructorReferenceExpression() instanceof JetSimpleNameExpression) {
refExpression = (JetSimpleNameExpression) constructorCalleeExpression.getConstructorReferenceExpression(); refExpression = (JetSimpleNameExpression)constructorCalleeExpression.getConstructorReferenceExpression();
} }
} }
if (refExpression != null) { if (refExpression != null) {
@@ -357,18 +386,21 @@ public class JetFunctionParameterInfoHandler implements
ArrayList<DeclarationDescriptor> itemsToShow = new ArrayList<DeclarationDescriptor>(); ArrayList<DeclarationDescriptor> itemsToShow = new ArrayList<DeclarationDescriptor>();
for (DeclarationDescriptor variant : variants) { for (DeclarationDescriptor variant : variants) {
if (variant instanceof FunctionDescriptor) { if (variant instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) variant; FunctionDescriptor functionDescriptor = (FunctionDescriptor)variant;
if (functionDescriptor.getName().equals(refName)) { if (functionDescriptor.getName().equals(refName)) {
//todo: renamed functions? //todo: renamed functions?
if (placeDescriptor != null && !JetVisibilityChecker.isVisible(placeDescriptor, functionDescriptor)) continue; if (placeDescriptor != null && !JetVisibilityChecker.isVisible(placeDescriptor, functionDescriptor)) continue;
itemsToShow.add(functionDescriptor); itemsToShow.add(functionDescriptor);
} }
} else if (variant instanceof ClassDescriptor) { }
ClassDescriptor classDescriptor = (ClassDescriptor) variant; else if (variant instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor)variant;
if (classDescriptor.getName().equals(refName)) { if (classDescriptor.getName().equals(refName)) {
//todo: renamed classes? //todo: renamed classes?
for (ConstructorDescriptor constructorDescriptor : classDescriptor.getConstructors()) { for (ConstructorDescriptor constructorDescriptor : classDescriptor.getConstructors()) {
if (placeDescriptor != null && !JetVisibilityChecker.isVisible(placeDescriptor, constructorDescriptor)) continue; if (placeDescriptor != null && !JetVisibilityChecker.isVisible(placeDescriptor, constructorDescriptor)) {
continue;
}
itemsToShow.add(constructorDescriptor); itemsToShow.add(constructorDescriptor);
} }
} }
@@ -390,9 +422,9 @@ public class JetFunctionParameterInfoHandler implements
parent = parent.getParent(); parent = parent.getParent();
} }
if (parent == null) return null; if (parent == null) return null;
JetValueArgumentList argumentList = (JetValueArgumentList) parent; JetValueArgumentList argumentList = (JetValueArgumentList)parent;
if (element instanceof JetValueArgument) { if (element instanceof JetValueArgument) {
JetValueArgument arg = (JetValueArgument) element; JetValueArgument arg = (JetValueArgument)element;
int i = argumentList.getArguments().indexOf(arg); int i = argumentList.getArguments().indexOf(arg);
context.setCurrentParameter(i); context.setCurrentParameter(i);
context.setHighlightedParameter(arg); context.setHighlightedParameter(arg);
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetProperty;
@@ -39,7 +40,7 @@ import org.jetbrains.jet.plugin.JetBundle;
*/ */
public class ChangeVariableMutabilityFix implements IntentionAction { public class ChangeVariableMutabilityFix implements IntentionAction {
private boolean isVar; private boolean isVar;
public ChangeVariableMutabilityFix(boolean isVar) { public ChangeVariableMutabilityFix(boolean isVar) {
this.isVar = isVar; this.isVar = isVar;
} }
@@ -47,7 +48,7 @@ public class ChangeVariableMutabilityFix implements IntentionAction {
public ChangeVariableMutabilityFix() { public ChangeVariableMutabilityFix() {
this(false); this(false);
} }
@NotNull @NotNull
@Override @Override
public String getText() { public String getText() {
@@ -63,7 +64,7 @@ public class ChangeVariableMutabilityFix implements IntentionAction {
@Override @Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (!(file instanceof JetFile)) return false; if (!(file instanceof JetFile)) return false;
JetProperty property = getCorrespondingProperty(editor, (JetFile) file); JetProperty property = getCorrespondingProperty(editor, (JetFile)file);
return property != null && !property.isVar(); return property != null && !property.isVar();
} }
@@ -73,13 +74,14 @@ public class ChangeVariableMutabilityFix implements IntentionAction {
if (property != null) return property; if (property != null) return property;
JetSimpleNameExpression simpleNameExpression = PsiTreeUtil.getParentOfType(elementAtCaret, JetSimpleNameExpression.class); JetSimpleNameExpression simpleNameExpression = PsiTreeUtil.getParentOfType(elementAtCaret, JetSimpleNameExpression.class);
if (simpleNameExpression != null) { if (simpleNameExpression != null) {
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) BindingContext bindingContext =
AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, simpleNameExpression, true); VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, simpleNameExpression, true);
if (descriptor != null) { if (descriptor != null) {
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
return (JetProperty) declaration; return (JetProperty)declaration;
} }
} }
} }
@@ -92,7 +94,7 @@ public class ChangeVariableMutabilityFix implements IntentionAction {
assert property != null && !property.isVar(); assert property != null && !property.isVar();
JetProperty newElement = JetPsiFactory.createProperty(project, property.getText().replaceFirst( JetProperty newElement = JetPsiFactory.createProperty(project, property.getText().replaceFirst(
property.isVar() ? "var" : "val", property.isVar() ? "val" : "var")); property.isVar() ? "var" : "val", property.isVar() ? "val" : "var"));
property.replace(newElement); property.replace(newElement);
} }
@@ -19,6 +19,7 @@ package org.jetbrains.jet.plugin.quickfix;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.lang.DefaultModuleConfiguration; import org.jetbrains.jet.lang.DefaultModuleConfiguration;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetImportDirective; import org.jetbrains.jet.lang.psi.JetImportDirective;
@@ -54,8 +55,8 @@ public class ImportInsertHelper {
if (JetPluginUtil.checkTypeIsStandard(type, file.getProject()) || ErrorUtils.isErrorType(type)) { if (JetPluginUtil.checkTypeIsStandard(type, file.getProject()) || ErrorUtils.isErrorType(type)) {
return; return;
} }
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache(file, AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
PsiElement element = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, type.getMemberScope().getContainingDeclaration()); PsiElement element = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, type.getMemberScope().getContainingDeclaration());
if (element != null && element.getContainingFile() == file) { //declaration is in the same file, so no import is needed if (element != null && element.getContainingFile() == file) { //declaration is in the same file, so no import is needed
return; return;
@@ -67,7 +68,7 @@ public class ImportInsertHelper {
* Add import directive into the PSI tree for the given namespace. * Add import directive into the PSI tree for the given namespace.
* *
* @param importFqn full name of the import * @param importFqn full name of the import
* @param file File where directive should be added. * @param file File where directive should be added.
*/ */
public static void addImportDirective(@NotNull FqName importFqn, @NotNull JetFile file) { public static void addImportDirective(@NotNull FqName importFqn, @NotNull JetFile file) {
addImportDirective(new ImportPath(importFqn, false), null, file); addImportDirective(new ImportPath(importFqn, false), null, file);
@@ -16,13 +16,13 @@
package org.jetbrains.jet.plugin.quickfix; package org.jetbrains.jet.plugin.quickfix;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.extapi.psi.ASTDelegatePsiElement; import com.intellij.extapi.psi.ASTDelegatePsiElement;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Diagnostic;
@@ -57,13 +57,14 @@ public class QuickFixUtil {
public static JetType getDeclarationReturnType(JetNamedDeclaration declaration) { public static JetType getDeclarationReturnType(JetNamedDeclaration declaration) {
PsiFile file = declaration.getContainingFile(); PsiFile file = declaration.getContainingFile();
if (!(file instanceof JetFile)) return null; if (!(file instanceof JetFile)) return null;
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile) file, AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) BindingContext bindingContext =
AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile)file, AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration); DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration);
if (!(descriptor instanceof CallableDescriptor)) return null; if (!(descriptor instanceof CallableDescriptor)) return null;
JetType type = ((CallableDescriptor) descriptor).getReturnType(); JetType type = ((CallableDescriptor)descriptor).getReturnType();
if (type instanceof DeferredType) { if (type instanceof DeferredType) {
type = ((DeferredType) type).getActualType(); type = ((DeferredType)type).getActualType();
} }
return type; return type;
} }
@@ -19,15 +19,16 @@ package org.jetbrains.jet.plugin.refactoring;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lexer.JetLexer; import org.jetbrains.jet.lexer.JetLexer;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
@@ -59,16 +60,17 @@ public class JetNameSuggester {
* 1c. Arrays => arrayOfInnerType * 1c. Arrays => arrayOfInnerType
* 2. Reference expressions according to reference name camel humps * 2. Reference expressions according to reference name camel humps
* 3. Method call expression according to method callee expression * 3. Method call expression according to method callee expression
*
* @param expression to suggest name for variable * @param expression to suggest name for variable
* @param validator to check scope for such names * @param validator to check scope for such names
* @return possible names * @return possible names
*/ */
public static String[] suggestNames(JetExpression expression, JetNameValidator validator) { public static String[] suggestNames(JetExpression expression, JetNameValidator validator) {
ArrayList<String> result = new ArrayList<String>(); ArrayList<String> result = new ArrayList<String>();
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile) expression.getContainingFile(), BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile)expression.getContainingFile(),
AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
if (jetType != null) { if (jetType != null) {
addNamesForType(result, jetType, validator); addNamesForType(result, jetType, validator);
@@ -78,67 +80,85 @@ public class JetNameSuggester {
if (result.isEmpty()) addName(result, "value", validator); if (result.isEmpty()) addName(result, "value", validator);
return ArrayUtil.toStringArray(result); return ArrayUtil.toStringArray(result);
} }
private static void addNamesForType(ArrayList<String> result, JetType jetType, JetNameValidator validator) { private static void addNamesForType(ArrayList<String> result, JetType jetType, JetNameValidator validator) {
JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance(); JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance();
JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
if (ErrorUtils.containsErrorType(jetType)) return; if (ErrorUtils.containsErrorType(jetType)) return;
if (typeChecker.equalTypes(standardLibrary.getBooleanType(), jetType)) { if (typeChecker.equalTypes(standardLibrary.getBooleanType(), jetType)) {
addName(result, "b", validator); addName(result, "b", validator);
} else if (typeChecker.equalTypes(standardLibrary.getIntType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getIntType(), jetType)) {
addName(result, "i", validator); addName(result, "i", validator);
} else if (typeChecker.equalTypes(standardLibrary.getByteType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getByteType(), jetType)) {
addName(result, "byte", validator); addName(result, "byte", validator);
} else if (typeChecker.equalTypes(standardLibrary.getLongType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getLongType(), jetType)) {
addName(result, "l", validator); addName(result, "l", validator);
} else if (typeChecker.equalTypes(standardLibrary.getFloatType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getFloatType(), jetType)) {
addName(result, "fl", validator); addName(result, "fl", validator);
} else if (typeChecker.equalTypes(standardLibrary.getDoubleType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getDoubleType(), jetType)) {
addName(result, "d", validator); addName(result, "d", validator);
} else if (typeChecker.equalTypes(standardLibrary.getShortType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getShortType(), jetType)) {
addName(result, "sh", validator); addName(result, "sh", validator);
} else if (typeChecker.equalTypes(standardLibrary.getCharType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getCharType(), jetType)) {
addName(result, "c", validator); addName(result, "c", validator);
} else if (typeChecker.equalTypes(standardLibrary.getStringType(), jetType)) { }
else if (typeChecker.equalTypes(standardLibrary.getStringType(), jetType)) {
addName(result, "s", validator); addName(result, "s", validator);
} else { }
else {
if (jetType.getArguments().size() == 1) { if (jetType.getArguments().size() == 1) {
JetType argument = jetType.getArguments().get(0).getType(); JetType argument = jetType.getArguments().get(0).getType();
if (typeChecker.equalTypes(standardLibrary.getArrayType(argument), jetType)) { if (typeChecker.equalTypes(standardLibrary.getArrayType(argument), jetType)) {
if (typeChecker.equalTypes(standardLibrary.getBooleanType(), argument)) { if (typeChecker.equalTypes(standardLibrary.getBooleanType(), argument)) {
addName(result, "booleans", validator); addName(result, "booleans", validator);
} else if (typeChecker.equalTypes(standardLibrary.getIntType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getIntType(), argument)) {
addName(result, "ints", validator); addName(result, "ints", validator);
} else if (typeChecker.equalTypes(standardLibrary.getByteType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getByteType(), argument)) {
addName(result, "bytes", validator); addName(result, "bytes", validator);
} else if (typeChecker.equalTypes(standardLibrary.getLongType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getLongType(), argument)) {
addName(result, "longs", validator); addName(result, "longs", validator);
} else if (typeChecker.equalTypes(standardLibrary.getFloatType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getFloatType(), argument)) {
addName(result, "floats", validator); addName(result, "floats", validator);
} else if (typeChecker.equalTypes(standardLibrary.getDoubleType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getDoubleType(), argument)) {
addName(result, "doubles", validator); addName(result, "doubles", validator);
} else if (typeChecker.equalTypes(standardLibrary.getShortType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getShortType(), argument)) {
addName(result, "shorts", validator); addName(result, "shorts", validator);
} else if (typeChecker.equalTypes(standardLibrary.getCharType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getCharType(), argument)) {
addName(result, "chars", validator); addName(result, "chars", validator);
} else if (typeChecker.equalTypes(standardLibrary.getStringType(), argument)) { }
else if (typeChecker.equalTypes(standardLibrary.getStringType(), argument)) {
addName(result, "strings", validator); addName(result, "strings", validator);
} else { }
else {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(argument); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(argument);
if (classDescriptor != null) { if (classDescriptor != null) {
String className = classDescriptor.getName(); String className = classDescriptor.getName();
addName(result, "arrayOf" + StringUtil.capitalize(className) + "s", validator); addName(result, "arrayOf" + StringUtil.capitalize(className) + "s", validator);
} }
} }
} else { }
else {
addForClassType(result, jetType, validator); addForClassType(result, jetType, validator);
} }
} else { }
else {
addForClassType(result, jetType, validator); addForClassType(result, jetType, validator);
} }
} }
} }
private static void addForClassType(ArrayList<String> result, JetType jetType, JetNameValidator validator) { private static void addForClassType(ArrayList<String> result, JetType jetType, JetNameValidator validator) {
@@ -152,42 +172,48 @@ public class JetNameSuggester {
private static void addCamelNames(ArrayList<String> result, String name, JetNameValidator validator) { private static void addCamelNames(ArrayList<String> result, String name, JetNameValidator validator) {
if (name == "") return; if (name == "") return;
String s = deleteNonLetterFromString(name); String s = deleteNonLetterFromString(name);
if (s.startsWith("get") || s.startsWith("set")) s = s.substring(0, 3); if (s.startsWith("get") || s.startsWith("set")) {
s = s.substring(0, 3);
}
else if (s.startsWith("is")) s = s.substring(0, 2); else if (s.startsWith("is")) s = s.substring(0, 2);
for (int i = 0; i < s.length(); ++i) { for (int i = 0; i < s.length(); ++i) {
if (i == 0) { if (i == 0) {
addName(result, StringUtil.decapitalize(s), validator); addName(result, StringUtil.decapitalize(s), validator);
} else if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') { }
else if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') {
addName(result, StringUtil.decapitalize(s.substring(i)), validator); addName(result, StringUtil.decapitalize(s.substring(i)), validator);
} }
} }
} }
private static String deleteNonLetterFromString(String s) { private static String deleteNonLetterFromString(String s) {
Pattern pattern = Pattern.compile("[^a-zA-Z]"); Pattern pattern = Pattern.compile("[^a-zA-Z]");
Matcher matcher = pattern.matcher(s); Matcher matcher = pattern.matcher(s);
return matcher.replaceAll(""); return matcher.replaceAll("");
} }
private static void addNamesForExpression(ArrayList<String> result, JetExpression expression, JetNameValidator validator) { private static void addNamesForExpression(ArrayList<String> result, JetExpression expression, JetNameValidator validator) {
if (expression instanceof JetQualifiedExpression) { if (expression instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression; JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression)expression;
addNamesForExpression(result, qualifiedExpression.getSelectorExpression(), validator); addNamesForExpression(result, qualifiedExpression.getSelectorExpression(), validator);
} else if (expression instanceof JetSimpleNameExpression) { }
JetSimpleNameExpression reference = (JetSimpleNameExpression) expression; else if (expression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression reference = (JetSimpleNameExpression)expression;
String referenceName = reference.getReferencedName(); String referenceName = reference.getReferencedName();
if (referenceName == null) return; if (referenceName == null) return;
if (referenceName.equals(referenceName.toUpperCase())) { if (referenceName.equals(referenceName.toUpperCase())) {
addName(result, referenceName, validator); addName(result, referenceName, validator);
} else { }
else {
addCamelNames(result, referenceName, validator); addCamelNames(result, referenceName, validator);
} }
} else if (expression instanceof JetCallExpression) { }
JetCallExpression call = (JetCallExpression) expression; else if (expression instanceof JetCallExpression) {
JetCallExpression call = (JetCallExpression)expression;
addNamesForExpression(result, call.getCalleeExpression(), validator); addNamesForExpression(result, call.getCalleeExpression(), validator);
} }
} }
public static boolean isIdentifier(String name) { public static boolean isIdentifier(String name) {
ApplicationManager.getApplication().assertReadAccessAllowed(); ApplicationManager.getApplication().assertReadAccessAllowed();
if (name == null || name.isEmpty()) return false; if (name == null || name.isEmpty()) return false;
@@ -28,13 +28,14 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.NamespaceType; import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
@@ -66,15 +67,16 @@ public class JetRefactoringUtil {
while (selectionStart < selectionEnd && Character.isSpaceChar(text.charAt(selectionStart))) ++selectionStart; while (selectionStart < selectionEnd && Character.isSpaceChar(text.charAt(selectionStart))) ++selectionStart;
while (selectionStart < selectionEnd && Character.isSpaceChar(text.charAt(selectionEnd - 1))) --selectionEnd; while (selectionStart < selectionEnd && Character.isSpaceChar(text.charAt(selectionEnd - 1))) --selectionEnd;
callback.run(findExpression(editor, file, selectionStart, selectionEnd)); callback.run(findExpression(editor, file, selectionStart, selectionEnd));
} else { }
else {
int offset = editor.getCaretModel().getOffset(); int offset = editor.getCaretModel().getOffset();
smartSelectExpression(editor, file, offset, callback); smartSelectExpression(editor, file, offset, callback);
} }
} }
private static void smartSelectExpression(@NotNull Editor editor, @NotNull PsiFile file, int offset, private static void smartSelectExpression(@NotNull Editor editor, @NotNull PsiFile file, int offset,
@NotNull final SelectExpressionCallback callback) @NotNull final SelectExpressionCallback callback)
throws IntroduceRefactoringException { throws IntroduceRefactoringException {
if (offset < 0) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression")); if (offset < 0) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
PsiElement element = file.findElementAt(offset); PsiElement element = file.findElementAt(offset);
if (element == null) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression")); if (element == null) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
@@ -88,34 +90,38 @@ public class JetRefactoringUtil {
if (element instanceof JetExpression && !(element instanceof JetStatementExpression)) { if (element instanceof JetExpression && !(element instanceof JetStatementExpression)) {
boolean addExpression = true; boolean addExpression = true;
if (element.getParent() instanceof JetQualifiedExpression) { if (element.getParent() instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) element.getParent(); JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression)element.getParent();
if (qualifiedExpression.getReceiverExpression() != element) { if (qualifiedExpression.getReceiverExpression() != element) {
addExpression = false; addExpression = false;
} }
} else if (element.getParent() instanceof JetCallElement) { }
else if (element.getParent() instanceof JetCallElement) {
addExpression = false; addExpression = false;
} else if (element.getParent() instanceof JetOperationExpression) { }
JetOperationExpression operationExpression = (JetOperationExpression) element.getParent(); else if (element.getParent() instanceof JetOperationExpression) {
JetOperationExpression operationExpression = (JetOperationExpression)element.getParent();
if (operationExpression.getOperationReference() == element) { if (operationExpression.getOperationReference() == element) {
addExpression = false; addExpression = false;
} }
} }
if (addExpression) { if (addExpression) {
JetExpression expression = (JetExpression) element; JetExpression expression = (JetExpression)element;
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile) expression.getContainingFile(), BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile)expression.getContainingFile(),
AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
if (expressionType == null || !(expressionType instanceof NamespaceType) && if (expressionType == null || !(expressionType instanceof NamespaceType) &&
!JetTypeChecker.INSTANCE.equalTypes(JetStandardLibrary. !JetTypeChecker.INSTANCE.equalTypes(JetStandardLibrary.
getInstance().getTuple0Type(), expressionType)) { getInstance().getTuple0Type(), expressionType)) {
expressions.add(expression); expressions.add(expression);
} }
} }
} }
element = element.getParent(); element = element.getParent();
} }
if (expressions.size() == 0) throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression")); if (expressions.size() == 0) {
throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
}
final DefaultListModel model = new DefaultListModel(); final DefaultListModel model = new DefaultListModel();
for (JetExpression expression : expressions) { for (JetExpression expression : expressions) {
@@ -125,13 +131,13 @@ public class JetRefactoringUtil {
final ScopeHighlighter highlighter = new ScopeHighlighter(editor); final ScopeHighlighter highlighter = new ScopeHighlighter(editor);
final JList list = new JBList(model); final JList list = new JBList(model);
list.setCellRenderer(new DefaultListCellRenderer() { list.setCellRenderer(new DefaultListCellRenderer() {
@Override @Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
JetExpression element = (JetExpression) value; JetExpression element = (JetExpression)value;
if (element.isValid()) { if (element.isValid()) {
setText(getExpressionShortText(element)); setText(getExpressionShortText(element));
} }
@@ -145,7 +151,7 @@ public class JetRefactoringUtil {
highlighter.dropHighlight(); highlighter.dropHighlight();
int selectedIndex = list.getSelectedIndex(); int selectedIndex = list.getSelectedIndex();
if (selectedIndex < 0) return; if (selectedIndex < 0) return;
JetExpression expression = (JetExpression) model.get(selectedIndex); JetExpression expression = (JetExpression)model.get(selectedIndex);
ArrayList<PsiElement> toExtract = new ArrayList<PsiElement>(); ArrayList<PsiElement> toExtract = new ArrayList<PsiElement>();
toExtract.add(expression); toExtract.add(expression);
highlighter.highlight(expression, toExtract); highlighter.highlight(expression, toExtract);
@@ -153,11 +159,11 @@ public class JetRefactoringUtil {
}); });
JBPopupFactory.getInstance().createListPopupBuilder(list). JBPopupFactory.getInstance().createListPopupBuilder(list).
setTitle(JetRefactoringBundle.message("expressions.title")).setMovable(false).setResizable(false). setTitle(JetRefactoringBundle.message("expressions.title")).setMovable(false).setResizable(false).
setRequestFocus(true).setItemChoosenCallback(new Runnable() { setRequestFocus(true).setItemChoosenCallback(new Runnable() {
@Override @Override
public void run() { public void run() {
callback.run((JetExpression) list.getSelectedValue()); callback.run((JetExpression)list.getSelectedValue());
} }
}).addListener(new JBPopupAdapter() { }).addListener(new JBPopupAdapter() {
@Override @Override
@@ -165,7 +171,6 @@ public class JetRefactoringUtil {
highlighter.dropHighlight(); highlighter.dropHighlight();
} }
}).createPopup().showInBestPositionFor(editor); }).createPopup().showInBestPositionFor(editor);
} }
public static String getExpressionShortText(@NotNull JetExpression expression) { //todo: write appropriate implementation public static String getExpressionShortText(@NotNull JetExpression expression) { //todo: write appropriate implementation
@@ -178,24 +183,26 @@ public class JetRefactoringUtil {
@Nullable @Nullable
private static JetExpression findExpression(@NotNull Editor editor, @NotNull PsiFile file, private static JetExpression findExpression(@NotNull Editor editor, @NotNull PsiFile file,
int startOffset, int endOffset) throws IntroduceRefactoringException{ int startOffset, int endOffset) throws IntroduceRefactoringException {
PsiElement element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JetExpression.class); PsiElement element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JetExpression.class);
if (element == null || element.getTextRange().getStartOffset() != startOffset || if (element == null || element.getTextRange().getStartOffset() != startOffset ||
element.getTextRange().getEndOffset() != endOffset) { element.getTextRange().getEndOffset() != endOffset) {
//todo: if it's infix expression => add (), then commit document then return new created expression //todo: if it's infix expression => add (), then commit document then return new created expression
throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression")); throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
} else if (!(element instanceof JetExpression)) { }
else if (!(element instanceof JetExpression)) {
throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression")); throw new IntroduceRefactoringException(JetRefactoringBundle.message("cannot.refactor.not.expression"));
} else if (element instanceof JetBlockExpression) { }
List<JetElement> statements = ((JetBlockExpression) element).getStatements(); else if (element instanceof JetBlockExpression) {
List<JetElement> statements = ((JetBlockExpression)element).getStatements();
if (statements.size() == 1) { if (statements.size() == 1) {
JetElement elem = statements.get(0); JetElement elem = statements.get(0);
if (elem.getText().equals(element.getText()) && elem instanceof JetExpression) { if (elem.getText().equals(element.getText()) && elem instanceof JetExpression) {
return (JetExpression) elem; return (JetExpression)elem;
} }
} }
} }
return (JetExpression) element; return (JetExpression)element;
} }
public static class IntroduceRefactoringException extends Exception { public static class IntroduceRefactoringException extends Exception {
@@ -209,5 +216,4 @@ public class JetRefactoringUtil {
return myMessage; return myMessage;
} }
} }
} }
@@ -34,14 +34,15 @@ import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.CommonRefactoringUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzerFacadeWithCache;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.NamespaceType; import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.refactoring.*; import org.jetbrains.jet.plugin.refactoring.*;
@@ -65,7 +66,8 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
}; };
try { try {
JetRefactoringUtil.selectExpression(editor, file, callback); JetRefactoringUtil.selectExpression(editor, file, callback);
} catch (JetRefactoringUtil.IntroduceRefactoringException e) { }
catch (JetRefactoringUtil.IntroduceRefactoringException e) {
showErrorHint(project, editor, e.getMessage()); showErrorHint(project, editor, e.getMessage());
} }
} }
@@ -76,34 +78,37 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
return; return;
} }
if (_expression.getParent() instanceof JetParenthesizedExpression) { if (_expression.getParent() instanceof JetParenthesizedExpression) {
_expression = (JetExpression) _expression.getParent(); _expression = (JetExpression)_expression.getParent();
} }
final JetExpression expression = _expression; final JetExpression expression = _expression;
if (expression.getParent() instanceof JetQualifiedExpression) { if (expression.getParent() instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression.getParent(); JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression)expression.getParent();
if (qualifiedExpression.getReceiverExpression() != expression) { if (qualifiedExpression.getReceiverExpression() != expression) {
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression")); showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
return; return;
} }
} else if (expression.getParent() instanceof JetCallElement || expression instanceof JetStatementExpression) { }
else if (expression.getParent() instanceof JetCallElement || expression instanceof JetStatementExpression) {
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression")); showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
return; return;
} else if (expression.getParent() instanceof JetOperationExpression) { }
JetOperationExpression operationExpression = (JetOperationExpression) expression.getParent(); else if (expression.getParent() instanceof JetOperationExpression) {
JetOperationExpression operationExpression = (JetOperationExpression)expression.getParent();
if (operationExpression.getOperationReference() == expression) { if (operationExpression.getOperationReference() == expression) {
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression")); showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
return; return;
} }
} }
BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile) expression.getContainingFile(), BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile)expression.getContainingFile(),
AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); //can be null or error type final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); //can be null or error type
if (expressionType instanceof NamespaceType) { if (expressionType instanceof NamespaceType) {
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.namespace.expression")); showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.namespace.expression"));
return; return;
} if (expressionType != null && }
JetTypeChecker.INSTANCE.equalTypes(JetStandardLibrary.getInstance().getTuple0Type(), expressionType)) { if (expressionType != null &&
JetTypeChecker.INSTANCE.equalTypes(JetStandardLibrary.getInstance().getTuple0Type(), expressionType)) {
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.expression.has.unit.type")); showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.expression.has.unit.type"));
return; return;
} }
@@ -114,8 +119,8 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
return; return;
} }
final boolean isInplaceAvailableOnDataContext = final boolean isInplaceAvailableOnDataContext =
editor.getSettings().isVariableInplaceRenameEnabled() && editor.getSettings().isVariableInplaceRenameEnabled() &&
!ApplicationManager.getApplication().isUnitTestMode(); !ApplicationManager.getApplication().isUnitTestMode();
final ArrayList<JetExpression> allOccurrences = findOccurrences(occurrenceContainer, expression); final ArrayList<JetExpression> allOccurrences = findOccurrences(occurrenceContainer, expression);
Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() { Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() {
@Override @Override
@@ -125,10 +130,11 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
if (OccurrencesChooser.ReplaceChoice.ALL == replaceChoice) { if (OccurrencesChooser.ReplaceChoice.ALL == replaceChoice) {
if (allOccurrences.size() > 1) replaceOccurrence = true; if (allOccurrences.size() > 1) replaceOccurrence = true;
allReplaces = allOccurrences; allReplaces = allOccurrences;
} else { }
else {
allReplaces = Collections.singletonList(expression); allReplaces = Collections.singletonList(expression);
} }
PsiElement commonParent = PsiTreeUtil.findCommonParent(allReplaces); PsiElement commonParent = PsiTreeUtil.findCommonParent(allReplaces);
PsiElement commonContainer = getContainer(commonParent); PsiElement commonContainer = getContainer(commonParent);
JetNameValidatorImpl validator = new JetNameValidatorImpl(commonContainer, JetNameValidatorImpl validator = new JetNameValidatorImpl(commonContainer,
@@ -142,8 +148,8 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
final ArrayList<JetExpression> references = new ArrayList<JetExpression>(); final ArrayList<JetExpression> references = new ArrayList<JetExpression>();
final Ref<JetExpression> reference = new Ref<JetExpression>(); final Ref<JetExpression> reference = new Ref<JetExpression>();
final Runnable introduceRunnable = introduceVariable(project, expression, suggestedNames, allReplaces, commonContainer, final Runnable introduceRunnable = introduceVariable(project, expression, suggestedNames, allReplaces, commonContainer,
commonParent, replaceOccurrence, propertyRef, references, commonParent, replaceOccurrence, propertyRef, references,
reference); reference);
final boolean finalReplaceOccurrence = replaceOccurrence; final boolean finalReplaceOccurrence = replaceOccurrence;
CommandProcessor.getInstance().executeCommand(project, new Runnable() { CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override @Override
@@ -156,13 +162,13 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
if (isInplaceAvailableOnDataContext) { if (isInplaceAvailableOnDataContext) {
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
PsiDocumentManager.getInstance(project). PsiDocumentManager.getInstance(project).
doPostponedOperationsAndUnblockDocument(editor.getDocument()); doPostponedOperationsAndUnblockDocument(editor.getDocument());
JetInplaceVariableIntroducer variableIntroducer = JetInplaceVariableIntroducer variableIntroducer =
new JetInplaceVariableIntroducer(property, editor, project, INTRODUCE_VARIABLE, new JetInplaceVariableIntroducer(property, editor, project, INTRODUCE_VARIABLE,
references.toArray(new JetExpression[references.size()]), references.toArray(new JetExpression[references.size()]),
reference.get(), finalReplaceOccurrence, reference.get(), finalReplaceOccurrence,
property, /*todo*/false, /*todo*/false, property, /*todo*/false, /*todo*/false,
expressionType); expressionType);
variableIntroducer.performInplaceRefactoring(suggestedNamesSet); variableIntroducer.performInplaceRefactoring(suggestedNamesSet);
} }
} }
@@ -172,147 +178,163 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
}; };
if (isInplaceAvailableOnDataContext) { if (isInplaceAvailableOnDataContext) {
OccurrencesChooser.<JetExpression>simpleChooser(editor). OccurrencesChooser.<JetExpression>simpleChooser(editor).
showChooser(expression, allOccurrences, callback); showChooser(expression, allOccurrences, callback);
} else { }
else {
callback.pass(OccurrencesChooser.ReplaceChoice.ALL); callback.pass(OccurrencesChooser.ReplaceChoice.ALL);
} }
} }
private static Runnable introduceVariable(final @NotNull Project project, final JetExpression expression, private static Runnable introduceVariable(final @NotNull Project project, final JetExpression expression,
final String[] suggestedNames, final String[] suggestedNames,
final List<JetExpression> allReplaces, final PsiElement commonContainer, final List<JetExpression> allReplaces, final PsiElement commonContainer,
final PsiElement commonParent, final boolean replaceOccurrence, final PsiElement commonParent, final boolean replaceOccurrence,
final Ref<JetProperty> propertyRef, final Ref<JetProperty> propertyRef,
final ArrayList<JetExpression> references, final ArrayList<JetExpression> references,
final Ref<JetExpression> reference) { final Ref<JetExpression> reference) {
return new Runnable() { return new Runnable() {
@Override @Override
public void run() { public void run() {
String variableText = "val " + suggestedNames[0] + " = "; String variableText = "val " + suggestedNames[0] + " = ";
if (expression instanceof JetParenthesizedExpression) { if (expression instanceof JetParenthesizedExpression) {
JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression; JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression)expression;
JetExpression innerExpression = parenthesizedExpression.getExpression(); JetExpression innerExpression = parenthesizedExpression.getExpression();
if (innerExpression != null) variableText += innerExpression.getText(); if (innerExpression != null) {
else variableText += expression.getText(); variableText += innerExpression.getText();
} else variableText += expression.getText(); }
JetProperty property = JetPsiFactory.createProperty(project, variableText); else {
if (property == null) return; variableText += expression.getText();
PsiElement anchor = calculateAnchor(commonParent, commonContainer, allReplaces); }
if (anchor == null) return; }
boolean needBraces = !(commonContainer instanceof JetBlockExpression || else {
commonContainer instanceof JetClassBody || variableText += expression.getText();
commonContainer instanceof JetClassInitializer); }
if (!needBraces) { JetProperty property = JetPsiFactory.createProperty(project, variableText);
property = (JetProperty) commonContainer.addBefore(property, anchor); if (property == null) return;
commonContainer.addBefore(JetPsiFactory.createWhiteSpace(project, "\n"), anchor); PsiElement anchor = calculateAnchor(commonParent, commonContainer, allReplaces);
} else { if (anchor == null) return;
JetExpression emptyBody = JetPsiFactory.createEmptyBody(project); boolean needBraces = !(commonContainer instanceof JetBlockExpression ||
PsiElement firstChild = emptyBody.getFirstChild(); commonContainer instanceof JetClassBody ||
emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild); commonContainer instanceof JetClassInitializer);
if (replaceOccurrence && commonContainer != null) { if (!needBraces) {
for (JetExpression replace : allReplaces) { property = (JetProperty)commonContainer.addBefore(property, anchor);
boolean isActualExpression = expression == replace; commonContainer.addBefore(JetPsiFactory.createWhiteSpace(project, "\n"), anchor);
JetExpression element = (JetExpression) replace.replace(JetPsiFactory.createExpression(project, suggestedNames[0])); }
if (isActualExpression) reference.set(element); else {
} JetExpression emptyBody = JetPsiFactory.createEmptyBody(project);
PsiElement oldElement = commonContainer; PsiElement firstChild = emptyBody.getFirstChild();
if (commonContainer instanceof JetWhenEntry) { emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild);
JetExpression body = ((JetWhenEntry) commonContainer).getExpression(); if (replaceOccurrence && commonContainer != null) {
if (body != null) { for (JetExpression replace : allReplaces) {
oldElement = body; boolean isActualExpression = expression == replace;
} JetExpression element =
} else if (commonContainer instanceof JetNamedFunction) { (JetExpression)replace.replace(JetPsiFactory.createExpression(project, suggestedNames[0]));
JetExpression body = ((JetNamedFunction) commonContainer).getBodyExpression(); if (isActualExpression) reference.set(element);
if (body != null) { }
oldElement = body; PsiElement oldElement = commonContainer;
} if (commonContainer instanceof JetWhenEntry) {
} else if (commonContainer instanceof JetSecondaryConstructor) { JetExpression body = ((JetWhenEntry)commonContainer).getExpression();
JetExpression body = ((JetSecondaryConstructor) commonContainer).getBodyExpression(); if (body != null) {
if (body != null) { oldElement = body;
oldElement = body; }
} }
} else if (commonContainer instanceof JetContainerNode) { else if (commonContainer instanceof JetNamedFunction) {
JetContainerNode container = (JetContainerNode) commonContainer; JetExpression body = ((JetNamedFunction)commonContainer).getBodyExpression();
PsiElement[] children = container.getChildren(); if (body != null) {
for (PsiElement child : children) { oldElement = body;
if (child instanceof JetExpression) { }
oldElement = child; }
} else if (commonContainer instanceof JetSecondaryConstructor) {
} JetExpression body = ((JetSecondaryConstructor)commonContainer).getBodyExpression();
} if (body != null) {
//ugly logic to make sure we are working with right actual expression oldElement = body;
JetExpression actualExpression = reference.get(); }
int diff = actualExpression.getTextRange().getStartOffset() - oldElement.getTextRange().getStartOffset(); }
String actualExpressionText = actualExpression.getText(); else if (commonContainer instanceof JetContainerNode) {
PsiElement newElement = emptyBody.addAfter(oldElement, firstChild); JetContainerNode container = (JetContainerNode)commonContainer;
PsiElement elem = newElement.findElementAt(diff); PsiElement[] children = container.getChildren();
while (elem != null && !(elem instanceof JetExpression && for (PsiElement child : children) {
actualExpressionText.equals(elem.getText()))) { if (child instanceof JetExpression) {
elem = elem.getParent(); oldElement = child;
} }
if (elem != null) { }
reference.set((JetExpression) elem); }
} //ugly logic to make sure we are working with right actual expression
emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild); JetExpression actualExpression = reference.get();
property = (JetProperty) emptyBody.addAfter(property, firstChild); int diff = actualExpression.getTextRange().getStartOffset() - oldElement.getTextRange().getStartOffset();
emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild); String actualExpressionText = actualExpression.getText();
actualExpression = reference.get(); PsiElement newElement = emptyBody.addAfter(oldElement, firstChild);
diff = actualExpression.getTextRange().getStartOffset() - emptyBody.getTextRange().getStartOffset(); PsiElement elem = newElement.findElementAt(diff);
actualExpressionText = actualExpression.getText(); while (elem != null && !(elem instanceof JetExpression &&
emptyBody = (JetExpression) anchor.replace(emptyBody); actualExpressionText.equals(elem.getText()))) {
elem = emptyBody.findElementAt(diff); elem = elem.getParent();
while (elem != null && !(elem instanceof JetExpression && }
actualExpressionText.equals(elem.getText()))) { if (elem != null) {
elem = elem.getParent(); reference.set((JetExpression)elem);
} }
if (elem != null) { emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild);
reference.set((JetExpression) elem); property = (JetProperty)emptyBody.addAfter(property, firstChild);
} emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild);
} else { actualExpression = reference.get();
property = (JetProperty) emptyBody.addAfter(property, firstChild); diff = actualExpression.getTextRange().getStartOffset() - emptyBody.getTextRange().getStartOffset();
emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild); actualExpressionText = actualExpression.getText();
emptyBody = (JetExpression) anchor.replace(emptyBody); emptyBody = (JetExpression)anchor.replace(emptyBody);
} elem = emptyBody.findElementAt(diff);
for (PsiElement child : emptyBody.getChildren()) { while (elem != null && !(elem instanceof JetExpression &&
if (child instanceof JetProperty) { actualExpressionText.equals(elem.getText()))) {
property = (JetProperty) child; elem = elem.getParent();
} }
} if (elem != null) {
if (commonContainer instanceof JetNamedFunction) { reference.set((JetExpression)elem);
//we should remove equals sign }
JetNamedFunction function = (JetNamedFunction) commonContainer; }
if (!function.hasDeclaredReturnType()) { else {
//todo: add return type property = (JetProperty)emptyBody.addAfter(property, firstChild);
} emptyBody.addAfter(JetPsiFactory.createWhiteSpace(project, "\n"), firstChild);
function.getEqualsToken().delete(); emptyBody = (JetExpression)anchor.replace(emptyBody);
} else if (commonContainer instanceof JetContainerNode) { }
JetContainerNode node = (JetContainerNode) commonContainer; for (PsiElement child : emptyBody.getChildren()) {
if (node.getParent() instanceof JetIfExpression) { if (child instanceof JetProperty) {
PsiElement next = node.getNextSibling(); property = (JetProperty)child;
if (next != null) { }
PsiElement nextnext = next.getNextSibling(); }
if (nextnext != null && nextnext.getNode().getElementType() == JetTokens.ELSE_KEYWORD) { if (commonContainer instanceof JetNamedFunction) {
if (next instanceof PsiWhiteSpace) { //we should remove equals sign
next.replace(JetPsiFactory.createWhiteSpace(project, " ")) ; JetNamedFunction function = (JetNamedFunction)commonContainer;
} if (!function.hasDeclaredReturnType()) {
} //todo: add return type
} }
} function.getEqualsToken().delete();
} }
} else if (commonContainer instanceof JetContainerNode) {
for (JetExpression replace : allReplaces) { JetContainerNode node = (JetContainerNode)commonContainer;
if (replaceOccurrence && !needBraces) { if (node.getParent() instanceof JetIfExpression) {
boolean isActualExpression = expression == replace; PsiElement next = node.getNextSibling();
JetExpression element = (JetExpression) replace.replace(JetPsiFactory.createExpression(project, suggestedNames[0])); if (next != null) {
references.add(element); PsiElement nextnext = next.getNextSibling();
if (isActualExpression) reference.set(element); if (nextnext != null && nextnext.getNode().getElementType() == JetTokens.ELSE_KEYWORD) {
} else if (!needBraces) { if (next instanceof PsiWhiteSpace) {
replace.delete(); next.replace(JetPsiFactory.createWhiteSpace(project, " "));
} }
} }
propertyRef.set(property); }
} }
}; }
}
for (JetExpression replace : allReplaces) {
if (replaceOccurrence && !needBraces) {
boolean isActualExpression = expression == replace;
JetExpression element = (JetExpression)replace.replace(JetPsiFactory.createExpression(project, suggestedNames[0]));
references.add(element);
if (isActualExpression) reference.set(element);
}
else if (!needBraces) {
replace.delete();
}
}
propertyRef.set(property);
}
};
} }
private static PsiElement calculateAnchor(PsiElement commonParent, PsiElement commonContainer, private static PsiElement calculateAnchor(PsiElement commonParent, PsiElement commonContainer,
@@ -322,7 +344,8 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
while (anchor.getParent() != commonContainer) { while (anchor.getParent() != commonContainer) {
anchor = anchor.getParent(); anchor = anchor.getParent();
} }
} else { }
else {
anchor = commonContainer.getFirstChild(); anchor = commonContainer.getFirstChild();
int startOffset = commonContainer.getTextRange().getEndOffset(); int startOffset = commonContainer.getTextRange().getEndOffset();
for (JetExpression expr : allReplaces) { for (JetExpression expr : allReplaces) {
@@ -339,7 +362,7 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
private static ArrayList<JetExpression> findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression expression) { private static ArrayList<JetExpression> findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression expression) {
if (expression instanceof JetParenthesizedExpression) { if (expression instanceof JetParenthesizedExpression) {
JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression; JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression)expression;
JetExpression innerExpression = parenthesizedExpression.getExpression(); JetExpression innerExpression = parenthesizedExpression.getExpression();
if (innerExpression != null) { if (innerExpression != null) {
expression = innerExpression; expression = innerExpression;
@@ -349,9 +372,9 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
final ArrayList<JetExpression> result = new ArrayList<JetExpression>(); final ArrayList<JetExpression> result = new ArrayList<JetExpression>();
final BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile) expression.getContainingFile(), final BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFileWithCache((JetFile)expression.getContainingFile(),
AnalyzerFacadeForJVM.SINGLE_DECLARATION_PROVIDER) AnalyzerFacadeWithCache.SINGLE_DECLARATION_PROVIDER)
.getBindingContext(); .getBindingContext();
JetVisitorVoid visitor = new JetVisitorVoid() { JetVisitorVoid visitor = new JetVisitorVoid() {
@Override @Override
@@ -368,26 +391,36 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
if (element1.getNode().getElementType() == JetTokens.IDENTIFIER && if (element1.getNode().getElementType() == JetTokens.IDENTIFIER &&
element2.getNode().getElementType() == JetTokens.IDENTIFIER) { element2.getNode().getElementType() == JetTokens.IDENTIFIER) {
if (element1.getParent() instanceof JetSimpleNameExpression && if (element1.getParent() instanceof JetSimpleNameExpression &&
element2.getParent() instanceof JetSimpleNameExpression) { element2.getParent() instanceof JetSimpleNameExpression) {
JetSimpleNameExpression expr1 = (JetSimpleNameExpression) element1.getParent(); JetSimpleNameExpression expr1 = (JetSimpleNameExpression)element1.getParent();
JetSimpleNameExpression expr2 = (JetSimpleNameExpression) element2.getParent(); JetSimpleNameExpression expr2 = (JetSimpleNameExpression)element2.getParent();
DeclarationDescriptor descr1 = bindingContext.get(BindingContext.REFERENCE_TARGET, expr1); DeclarationDescriptor descr1 = bindingContext.get(BindingContext.REFERENCE_TARGET, expr1);
DeclarationDescriptor descr2 = bindingContext.get(BindingContext.REFERENCE_TARGET, expr2); DeclarationDescriptor descr2 = bindingContext.get(BindingContext.REFERENCE_TARGET, expr2);
if (descr1 != descr2) return 1; if (descr1 != descr2) {
else return 0; return 1;
}
else {
return 0;
}
} }
} }
if (!element1.textMatches(element2)) return 1; if (!element1.textMatches(element2)) {
else return 0; return 1;
}
else {
return 0;
}
} }
}, null, false)) { }, null, false)) {
PsiElement parent = expression.getParent(); PsiElement parent = expression.getParent();
if (parent instanceof JetParenthesizedExpression) { if (parent instanceof JetParenthesizedExpression) {
result.add((JetParenthesizedExpression) parent); result.add((JetParenthesizedExpression)parent);
} else { }
else {
result.add(expression); result.add(expression);
} }
} else { }
else {
super.visitExpression(expression); super.visitExpression(expression);
} }
} }
@@ -399,25 +432,28 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
@Nullable @Nullable
private static PsiElement getContainer(PsiElement place) { private static PsiElement getContainer(PsiElement place) {
if (place instanceof JetBlockExpression || place instanceof JetClassBody || if (place instanceof JetBlockExpression || place instanceof JetClassBody ||
place instanceof JetClassInitializer) { place instanceof JetClassInitializer) {
return place; return place;
} }
while (place != null) { while (place != null) {
PsiElement parent = place.getParent(); PsiElement parent = place.getParent();
if (parent instanceof JetContainerNode) { if (parent instanceof JetContainerNode) {
if (!isBadContainerNode((JetContainerNode) parent, place)) { if (!isBadContainerNode((JetContainerNode)parent, place)) {
return parent; return parent;
} }
} if (parent instanceof JetBlockExpression || parent instanceof JetWhenEntry || }
if (parent instanceof JetBlockExpression || parent instanceof JetWhenEntry ||
parent instanceof JetClassBody || parent instanceof JetClassInitializer) { parent instanceof JetClassBody || parent instanceof JetClassInitializer) {
return parent; return parent;
} else if (parent instanceof JetNamedFunction) { }
JetNamedFunction function = (JetNamedFunction) parent; else if (parent instanceof JetNamedFunction) {
JetNamedFunction function = (JetNamedFunction)parent;
if (function.getBodyExpression() == place) { if (function.getBodyExpression() == place) {
return parent; return parent;
} }
} else if (parent instanceof JetSecondaryConstructor) { }
JetSecondaryConstructor secondaryConstructor = (JetSecondaryConstructor) parent; else if (parent instanceof JetSecondaryConstructor) {
JetSecondaryConstructor secondaryConstructor = (JetSecondaryConstructor)parent;
if (secondaryConstructor.getBodyExpression() == place) { if (secondaryConstructor.getBodyExpression() == place) {
return parent; return parent;
} }
@@ -426,13 +462,14 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
} }
return null; return null;
} }
private static boolean isBadContainerNode(JetContainerNode parent, PsiElement place) { private static boolean isBadContainerNode(JetContainerNode parent, PsiElement place) {
if (parent.getParent() instanceof JetIfExpression && if (parent.getParent() instanceof JetIfExpression &&
((JetIfExpression) parent.getParent()).getCondition() == place) { ((JetIfExpression)parent.getParent()).getCondition() == place) {
return true; return true;
} else if (parent.getParent() instanceof JetLoopExpression && }
((JetLoopExpression) parent.getParent()).getBody() != place) { else if (parent.getParent() instanceof JetLoopExpression &&
((JetLoopExpression)parent.getParent()).getBody() != place) {
return true; return true;
} }
return false; return false;
@@ -444,27 +481,36 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
while (place != null) { while (place != null) {
PsiElement parent = place.getParent(); PsiElement parent = place.getParent();
if (parent instanceof JetContainerNode) { if (parent instanceof JetContainerNode) {
if (!(place instanceof JetBlockExpression) && !isBadContainerNode((JetContainerNode) parent, place)) { if (!(place instanceof JetBlockExpression) && !isBadContainerNode((JetContainerNode)parent, place)) {
result = parent; result = parent;
} }
} else if (parent instanceof JetClassBody || parent instanceof JetFile || parent instanceof JetClassInitializer) { }
if (result == null) return parent; else if (parent instanceof JetClassBody || parent instanceof JetFile || parent instanceof JetClassInitializer) {
else return result; if (result == null) {
} else if (parent instanceof JetBlockExpression) { return parent;
}
else {
return result;
}
}
else if (parent instanceof JetBlockExpression) {
result = parent; result = parent;
} else if (parent instanceof JetWhenEntry ) { }
else if (parent instanceof JetWhenEntry) {
if (!(place instanceof JetBlockExpression)) { if (!(place instanceof JetBlockExpression)) {
result = parent; result = parent;
} }
} else if (parent instanceof JetNamedFunction) { }
JetNamedFunction function = (JetNamedFunction) parent; else if (parent instanceof JetNamedFunction) {
JetNamedFunction function = (JetNamedFunction)parent;
if (function.getBodyExpression() == place) { if (function.getBodyExpression() == place) {
if (!(place instanceof JetBlockExpression)) { if (!(place instanceof JetBlockExpression)) {
result = parent; result = parent;
} }
} }
} else if (parent instanceof JetSecondaryConstructor) { }
JetSecondaryConstructor secondaryConstructor = (JetSecondaryConstructor) parent; else if (parent instanceof JetSecondaryConstructor) {
JetSecondaryConstructor secondaryConstructor = (JetSecondaryConstructor)parent;
if (secondaryConstructor.getBodyExpression() == place) { if (secondaryConstructor.getBodyExpression() == place) {
if (!(place instanceof JetBlockExpression)) { if (!(place instanceof JetBlockExpression)) {
result = parent; result = parent;