/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTNode;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit;
import org.eclipse.che.ide.ext.java.jdt.core.dom.IBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ITypeBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ImportDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Modifier;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Name;
import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.ScopeAnalyzer;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.util.CodeFormatterUtil;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* This <code>ImportRewriteContext</code> is aware of all the types visible in <code>compilationUnit</code> at
* <code>position</code>.
* <p>
* <b>Note:</b> This context only works if the AST was created with bindings!
* </p>
*/
public class ContextSensitiveImportRewriteContext extends ImportRewriteContext {
private final CompilationUnit fCompilationUnit;
private final int fPosition;
private IBinding[] fDeclarationsInScope;
private Name[] fImportedNames;
private final ImportRewrite fImportRewrite;
/**
* Creates an import rewrite context at the given node's start position.
*
* @param node
* the node to use as context
* @param importRewrite
* the import rewrite
* @since 3.6
*/
public ContextSensitiveImportRewriteContext(ASTNode node, ImportRewrite importRewrite) {
this((CompilationUnit)node.getRoot(), node.getStartPosition(), importRewrite);
}
/**
* Creates an import rewrite context at the given start position.
*
* @param compilationUnit
* the root
* @param position
* the context position
* @param importRewrite
* the import rewrite
*/
public ContextSensitiveImportRewriteContext(CompilationUnit compilationUnit, int position,
ImportRewrite importRewrite) {
fCompilationUnit = compilationUnit;
fPosition = position;
fImportRewrite = importRewrite;
fDeclarationsInScope = null;
fImportedNames = null;
}
@Override
public int findInContext(String qualifier, String name, int kind) {
IBinding[] declarationsInScope = getDeclarationsInScope();
for (int i = 0; i < declarationsInScope.length; i++) {
if (declarationsInScope[i] instanceof ITypeBinding) {
ITypeBinding typeBinding = (ITypeBinding)declarationsInScope[i];
if (isSameType(typeBinding, qualifier, name)) {
return RES_NAME_FOUND;
} else if (isConflicting(typeBinding, name)) {
return RES_NAME_CONFLICT;
}
} else if (declarationsInScope[i] != null) {
if (isConflicting(declarationsInScope[i], name)) {
return RES_NAME_CONFLICT;
}
}
}
Name[] names = getImportedNames();
for (int i = 0; i < names.length; i++) {
IBinding binding = names[i].resolveBinding();
if (binding instanceof ITypeBinding && !binding.isRecovered()) {
ITypeBinding typeBinding = (ITypeBinding)binding;
if (isConflictingType(typeBinding, qualifier, name)) {
return RES_NAME_CONFLICT;
}
}
}
List<AbstractTypeDeclaration> list = fCompilationUnit.types();
for (Iterator<AbstractTypeDeclaration> iter = list.iterator(); iter.hasNext(); ) {
AbstractTypeDeclaration type = iter.next();
ITypeBinding binding = type.resolveBinding();
if (binding != null) {
if (isSameType(binding, qualifier, name)) {
return RES_NAME_FOUND;
} else {
ITypeBinding decl = containingDeclaration(binding, qualifier, name);
while (decl != null && !decl.equals(binding)) {
int modifiers = decl.getModifiers();
if (Modifier.isPrivate(modifiers))
return RES_NAME_CONFLICT;
decl = decl.getDeclaringClass();
}
}
}
}
String[] addedImports = fImportRewrite.getAddedImports();
String qualifiedName = CodeFormatterUtil.concatenateName(qualifier, name);
for (int i = 0; i < addedImports.length; i++) {
String addedImport = addedImports[i];
if (qualifiedName.equals(addedImport)) {
return RES_NAME_FOUND;
} else {
if (isConflicting(name, addedImport))
return RES_NAME_CONFLICT;
}
}
//TODO maybe need search for types in project that has package 'java.lang'
// if (qualifier.equals("java.lang"))
// {
// // No explicit import statement required
// ITypeRoot typeRoot = fCompilationUnit.getTypeRoot();
// if (typeRoot != null)
// {
// IPackageFragment packageFragment = (IPackageFragment)typeRoot.getParent();
// try
// {
// ICompilationUnit[] compilationUnits = packageFragment.getCompilationUnits();
// for (int i = 0; i < compilationUnits.length; i++)
// {
// ICompilationUnit cu = compilationUnits[i];
// IType[] allTypes = cu.getAllTypes();
// for (int j = 0; j < allTypes.length; j++)
// {
// IType type = allTypes[j];
// String packageTypeName = type.getFullyQualifiedName();
// if (isConflicting(name, packageTypeName))
// return RES_NAME_CONFLICT;
// }
// }
// }
// catch (JavaModelException e)
// {
// }
// }
// }
return fImportRewrite.getDefaultImportRewriteContext().findInContext(qualifier, name, kind);
}
private boolean isConflicting(String name, String importt) {
int index = importt.lastIndexOf('.');
String importedName;
if (index == -1) {
importedName = importt;
} else {
importedName = importt.substring(index + 1, importt.length());
}
if (importedName.equals(name)) {
return true;
}
return false;
}
private ITypeBinding containingDeclaration(ITypeBinding binding, String qualifier, String name) {
ITypeBinding[] declaredTypes = binding.getDeclaredTypes();
for (int i = 0; i < declaredTypes.length; i++) {
ITypeBinding childBinding = declaredTypes[i];
if (isSameType(childBinding, qualifier, name)) {
return childBinding;
} else {
ITypeBinding result = containingDeclaration(childBinding, qualifier, name);
if (result != null) {
return result;
}
}
}
return null;
}
private boolean isConflicting(IBinding binding, String name) {
return binding.getName().equals(name);
}
private boolean isSameType(ITypeBinding binding, String qualifier, String name) {
String qualifiedName = CodeFormatterUtil.concatenateName(qualifier, name);
return binding.getQualifiedName().equals(qualifiedName);
}
private boolean isConflictingType(ITypeBinding binding, String qualifier, String name) {
binding = binding.getTypeDeclaration();
return !isSameType(binding, qualifier, name) && isConflicting(binding, name);
}
private IBinding[] getDeclarationsInScope() {
if (fDeclarationsInScope == null) {
ScopeAnalyzer analyzer = new ScopeAnalyzer(fCompilationUnit);
fDeclarationsInScope =
analyzer.getDeclarationsInScope(fPosition, ScopeAnalyzer.METHODS | ScopeAnalyzer.TYPES
| ScopeAnalyzer.VARIABLES);
}
return fDeclarationsInScope;
}
private Name[] getImportedNames() {
if (fImportedNames == null) {
// IJavaProject project = null;
// IJavaElement javaElement = fCompilationUnit.getJavaElement();
// if (javaElement != null)
// project = javaElement.getJavaProject();
//
// List<SimpleName> imports = new ArrayList<SimpleName>();
// ImportReferencesCollector.collect(fCompilationUnit, project, null, imports, null);
List<Name> imports = new ArrayList<Name>();
for (Iterator iterator = fCompilationUnit.imports().iterator(); iterator.hasNext(); ) {
ImportDeclaration im = (ImportDeclaration)iterator.next();
imports.add(im.getName());
}
fImportedNames = imports.toArray(new Name[imports.size()]);
}
return fImportedNames;
}
}