/*
* Copyright 2009-2017 the original author or authors.
*
* 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.codehaus.groovy.eclipse.core.inference;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.DynamicVariable;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.ImportNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.FieldExpression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.eclipse.core.compiler.CompilerUtils;
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
import org.codehaus.jdt.groovy.model.GroovyCompilationUnit;
import org.eclipse.jdt.groovy.search.ITypeLookup;
import org.eclipse.jdt.groovy.search.TypeLookupResult;
import org.eclipse.jdt.groovy.search.TypeLookupResult.TypeConfidence;
import org.eclipse.jdt.groovy.search.VariableScope;
import org.eclipse.jdt.groovy.search.VariableScope.VariableInfo;
public class STCTypeLookup implements ITypeLookup {
// only enabled for Groovy 2.0 or greater
private static final boolean isEnabled = (CompilerUtils.getActiveGroovyBundle().getVersion().getMajor() >= 2);
public void initialize(GroovyCompilationUnit unit, VariableScope topLevelScope) {
}
public TypeLookupResult lookupType(Expression expr, VariableScope scope, ClassNode objectExpressionType) {
if (isEnabled) {
ASTNode declaration = expr;
ClassNode declaringType = objectExpressionType;
TypeConfidence confidence = TypeConfidence.INFERRED;
Object inferredType = expr.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (expr instanceof ClassExpression) {
declaration = expr.getType();
} else if (expr instanceof FieldExpression) {
declaration = ((FieldExpression) expr).getField();
} else if (expr instanceof VariableExpression) {
Variable accessedVariable = ((VariableExpression) expr).getAccessedVariable();
if (accessedVariable instanceof DynamicVariable) {
// defer to other type lookup impls
confidence = TypeConfidence.UNKNOWN;
} else if (accessedVariable instanceof ASTNode) {
declaration = (ASTNode) accessedVariable;
if (inferredType instanceof ClassNode &&
VariableScope.isPlainClosure((ClassNode) inferredType)) {
VariableInfo info = scope.lookupName(accessedVariable.getName());
if (info != null && VariableScope.isParameterizedClosure(info.type)) {
inferredType = info.type; // Closure --> Closure<String>
}
}
}
} else if (expr instanceof MethodCallExpression ||
expr instanceof StaticMethodCallExpression || expr instanceof ConstructorCallExpression ||
!(inferredType instanceof ClassNode) && // check for VariableExpressionTransformer's substitution
expr instanceof ConstantExpression && (declaration = scope.getEnclosingNode()) instanceof PropertyExpression) {
Object call = declaration.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
if (call instanceof MethodNode) {
declaration = (MethodNode) call;
declaringType = ((MethodNode) call).getDeclaringClass();
if (!(inferredType instanceof ClassNode) && !(expr instanceof ConstructorCallExpression)) {
inferredType = ((MethodNode) call).getReturnType();
}
} else {
// defer to other type lookup impls
confidence = TypeConfidence.UNKNOWN;
}
}
if (inferredType instanceof ClassNode) {
return new TypeLookupResult((ClassNode) inferredType, declaringType, declaration, confidence, scope);
}
}
return null;
}
public TypeLookupResult lookupType(FieldNode node, VariableScope scope) {
if (isEnabled) {
Object inferredType = node.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (inferredType instanceof ClassNode) {
return new TypeLookupResult((ClassNode) inferredType, node.getDeclaringClass(), node, TypeConfidence.INFERRED, scope);
}
}
return null;
}
public TypeLookupResult lookupType(MethodNode node, VariableScope scope) {
if (isEnabled) {
Object inferredType = node.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
if (inferredType instanceof ClassNode) {
return new TypeLookupResult((ClassNode) inferredType, node.getDeclaringClass(), node, TypeConfidence.INFERRED, scope);
}
}
return null;
}
public TypeLookupResult lookupType(AnnotationNode node, VariableScope scope) {
return null;
}
public TypeLookupResult lookupType(ImportNode node, VariableScope scope) {
return null;
}
public TypeLookupResult lookupType(ClassNode node, VariableScope scope) {
return null;
}
public TypeLookupResult lookupType(Parameter node, VariableScope scope) {
return null;
}
}