org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.*;
public class ClassLiteralAccess extends Expression {
public TypeReference type;
public TypeBinding targetType;
FieldBinding syntheticField;
public ClassLiteralAccess(int sourceEnd, TypeReference type) {
this.type = type;
type.bits |= IgnoreRawTypeCheck; // no need to worry about raw type usage
this.sourceStart = type.sourceStart;
this.sourceEnd = sourceEnd;
}
@Override
public FlowInfo analyseCode(
BlockScope currentScope,
FlowContext flowContext,
FlowInfo flowInfo) {
// if reachable, request the addition of a synthetic field for caching the class descriptor
SourceTypeBinding sourceType = currentScope.outerMostClassScope().enclosingSourceType();
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=22334
if (!sourceType.isInterface()
&& !this.targetType.isBaseType()
&& currentScope.compilerOptions().targetJDK < ClassFileConstants.JDK1_5) {
this.syntheticField = sourceType.addSyntheticFieldForClassLiteral(this.targetType, currentScope);
}
return flowInfo;
}
/**
* MessageSendDotClass code generation
*
* @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
* @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
* @param valueRequired boolean
*/
@Override
public void generateCode(
BlockScope currentScope,
CodeStream codeStream,
boolean valueRequired) {
int pc = codeStream.position;
// in interface case, no caching occurs, since cannot make a cache field for interface
if (valueRequired) {
codeStream.generateClassLiteralAccessForType(currentScope, this.type.resolvedType, this.syntheticField);
codeStream.generateImplicitConversion(this.implicitConversion);
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
@Override
public StringBuffer printExpression(int indent, StringBuffer output) {
return this.type.print(0, output).append(".class"); //$NON-NLS-1$
}
@Override
public TypeBinding resolveType(BlockScope scope) {
this.constant = Constant.NotAConstant;
if ((this.targetType = this.type.resolveType(scope, true /* check bounds*/)) == null)
return null;
/* https://bugs.eclipse.org/bugs/show_bug.cgi?id=320463
https://bugs.eclipse.org/bugs/show_bug.cgi?id=312076
JLS3 15.8.2 forbids the type named in the class literal expression from being a parameterized type.
And the grammar in 18.1 disallows (where X and Y are some concrete types) constructs of the form
Outer.class, Outer.Inner.class, Outer.Inner.class, Outer.Inner.class etc.
Corollary wise, we should resolve the type of the class literal expression to be a raw type as
class literals exist only for the raw underlying type.
*/
LookupEnvironment environment = scope.environment();
this.targetType = environment.convertToRawType(this.targetType, true /* force conversion of enclosing types*/);
if (this.targetType.isArrayType()) {
ArrayBinding arrayBinding = (ArrayBinding) this.targetType;
TypeBinding leafComponentType = arrayBinding.leafComponentType;
if (leafComponentType == TypeBinding.VOID) {
scope.problemReporter().cannotAllocateVoidArray(this);
return null;
} else if (leafComponentType.isTypeVariable()) {
scope.problemReporter().illegalClassLiteralForTypeVariable((TypeVariableBinding)leafComponentType, this);
}
} else if (this.targetType.isTypeVariable()) {
scope.problemReporter().illegalClassLiteralForTypeVariable((TypeVariableBinding)this.targetType, this);
}
ReferenceBinding classType = scope.getJavaLangClass();
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328689
if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
// Integer.class --> Class, perform boxing of base types (int.class --> Class)
TypeBinding boxedType = null;
if (this.targetType.id == T_void) {
boxedType = environment.getResolvedJavaBaseType(JAVA_LANG_VOID, scope);
} else {
boxedType = scope.boxing(this.targetType);
}
if (environment.usesNullTypeAnnotations())
boxedType = environment.createAnnotatedType(boxedType, new AnnotationBinding[] { environment.getNonNullAnnotation() });
this.resolvedType = environment.createParameterizedType(classType, new TypeBinding[]{ boxedType }, null/*not a member*/);
} else {
this.resolvedType = classType;
}
return this.resolvedType;
}
@Override
public void traverse(
ASTVisitor visitor,
BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
this.type.traverse(visitor, blockScope);
}
visitor.endVisit(this, blockScope);
}
}