blob: 4084441fecb81934ee74ad7d002dc671c20d9f28 [file] [log] [blame]
/*
* Copyright (c) 2010-2020 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
*/
package org.eclipse.scout.sdk.core.model.ecj;
import static java.util.Collections.emptyList;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.Javadoc;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.scout.sdk.core.model.api.ICompilationUnit;
import org.eclipse.scout.sdk.core.model.api.ISourceRange;
import org.eclipse.scout.sdk.core.model.api.internal.CompilationUnitImplementor;
import org.eclipse.scout.sdk.core.model.spi.AbstractJavaEnvironment;
import org.eclipse.scout.sdk.core.model.spi.CompilationUnitSpi;
import org.eclipse.scout.sdk.core.model.spi.JavaElementSpi;
import org.eclipse.scout.sdk.core.model.spi.PackageSpi;
import org.eclipse.scout.sdk.core.model.spi.TypeSpi;
import org.eclipse.scout.sdk.core.util.Ensure;
import org.eclipse.scout.sdk.core.util.FinalValue;
/**
*
*/
public class DeclarationCompilationUnitWithEcj extends AbstractJavaElementWithEcj<ICompilationUnit> implements CompilationUnitSpi {
private final CompilationUnitDeclaration m_astNode;
private final FinalValue<PackageSpi> m_package;
private final FinalValue<String> m_fileName;
private final FinalValue<TypeSpi> m_mainType;
private final FinalValue<List<DeclarationTypeWithEcj>> m_types;
private final FinalValue<List<DeclarationImportWithEcj>> m_imports;
private final FinalValue<ISourceRange> m_source;
private final FinalValue<ISourceRange> m_javaDocSource;
protected DeclarationCompilationUnitWithEcj(AbstractJavaEnvironment env, CompilationUnitDeclaration astNode) {
super(env);
m_astNode = Ensure.notNull(astNode);
m_package = new FinalValue<>();
m_fileName = new FinalValue<>();
m_mainType = new FinalValue<>();
m_types = new FinalValue<>();
m_imports = new FinalValue<>();
m_source = new FinalValue<>();
m_javaDocSource = new FinalValue<>();
}
protected static TypeSpi findTypeBySimpleNameInternal(String simpleName, Scope scopeForTypeLookup, JavaEnvironmentWithEcj env) {
TypeBinding type = scopeForTypeLookup.getType(simpleName.toCharArray());
if (type instanceof MissingTypeBinding || type instanceof ProblemReferenceBinding) {
return null;
}
return SpiWithEcjUtils.bindingToType(env, type);
}
@Override
public JavaElementSpi internalFindNewElement() {
for (DeclarationTypeWithEcj oldType : getTypes()) {
TypeSpi newType = (TypeSpi) oldType.internalFindNewElement();
if (newType != null) {
return newType.getCompilationUnit();
}
}
return null;
}
@Override
protected ICompilationUnit internalCreateApi() {
return new CompilationUnitImplementor(this);
}
@Override
public boolean isSynthetic() {
return false;
}
public CompilationUnitDeclaration getInternalCompilationUnitDeclaration() {
return m_astNode;
}
@Override
public PackageSpi getPackage() {
return m_package.computeIfAbsentAndGet(() -> {
ImportReference currentPackage = m_astNode.currentPackage;
if (currentPackage != null) {
char[][] importName = currentPackage.getImportName();
if (importName != null && importName.length > 0) {
return javaEnvWithEcj().createPackage(CharOperation.toString(importName));
}
}
return javaEnvWithEcj().createDefaultPackage();
});
}
@Override
public TypeSpi findTypeBySimpleName(String simpleName) {
TypeSpi result = findTypeBySimpleNameInternal(simpleName, m_astNode.scope, javaEnvWithEcj());
if (result != null) {
return result;
}
// check inner types recursive
for (SourceTypeBinding stb : m_astNode.scope.topLevelTypes) {
result = findTypeInSourceTypeBindingRec(stb, simpleName);
if (result != null) {
return result;
}
}
return null;
}
protected TypeSpi findTypeInSourceTypeBindingRec(Binding b, String simpleName) {
if (!(b instanceof SourceTypeBinding)) {
return null;
}
SourceTypeBinding stb = (SourceTypeBinding) b;
TypeSpi result = findTypeBySimpleNameInternal(simpleName, stb.scope, javaEnvWithEcj());
if (result != null) {
return result;
}
for (ReferenceBinding mb : stb.memberTypes) {
result = findTypeInSourceTypeBindingRec(mb, simpleName);
if (result != null) {
return result;
}
}
return null;
}
@Override
public String getElementName() {
return m_fileName.computeIfAbsentAndGet(() -> {
char[] array = m_astNode.getFileName();
int i = Math.max(CharOperation.lastIndexOf('/', array), CharOperation.lastIndexOf('\\', array));
if (i >= 0) {
return new String(array, i + 1, array.length - i - 1);
}
return new String(array);
});
}
@Override
public TypeSpi getMainType() {
return m_mainType.computeIfAbsentAndGet(() -> {
String mainTypeName = new String(m_astNode.getMainTypeName());
for (TypeSpi t : getTypes()) {
if (mainTypeName.equals(t.getElementName())) {
return t;
}
}
return null;
});
}
@Override
public List<DeclarationTypeWithEcj> getTypes() {
return m_types.computeIfAbsentAndGet(() -> {
TypeDeclaration[] types = m_astNode.types;
if (types == null || types.length < 1) {
return emptyList();
}
List<DeclarationTypeWithEcj> result = new ArrayList<>(types.length);
for (TypeDeclaration td : types) {
result.add(javaEnvWithEcj().createDeclarationType(this, null, td));
}
return result;
});
}
@Override
public List<DeclarationImportWithEcj> getImports() {
return m_imports.computeIfAbsentAndGet(() -> {
ImportReference[] imports = m_astNode.imports;
if (imports == null || imports.length < 1) {
return emptyList();
}
List<DeclarationImportWithEcj> result = new ArrayList<>(imports.length);
for (ImportReference imp : imports) {
DeclarationImportWithEcj importDeclaration = javaEnvWithEcj().createDeclarationImport(this, imp);
result.add(importDeclaration);
}
return result;
});
}
@Override
public ISourceRange getSource() {
return m_source.computeIfAbsentAndGet(() -> javaEnvWithEcj().getSource(this, m_astNode.sourceStart, m_astNode.sourceEnd));
}
@Override
public ISourceRange getJavaDoc() {
return m_javaDocSource.computeIfAbsentAndGet(() -> {
Javadoc doc = m_astNode.javadoc;
if (doc != null) {
return javaEnvWithEcj().getSource(this, doc.sourceStart, doc.sourceEnd);
}
else if (m_astNode.currentPackage != null && m_astNode.currentPackage.declarationSourceStart > 0) {
return javaEnvWithEcj().getSource(this, 0, m_astNode.currentPackage.declarationSourceStart - 1);
}
else {
return null;
}
});
}
}