All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2015, 2019 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.aspectj.org.eclipse.jdt.internal.compiler.ast;

import static org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemSeverities.*;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.aspectj.org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ModuleScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceModuleBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortMethod;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortType;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.HashtableOfObject;

public class ModuleDeclaration extends ASTNode implements ReferenceContext {

	public ExportsStatement[] exports;
	public RequiresStatement[] requires;
	public UsesStatement[] uses;
	public ProvidesStatement[] services;
	public OpensStatement[] opens;
	public Annotation[] annotations;
	public int exportsCount;
	public int requiresCount;
	public int usesCount;
	public int servicesCount;
	public int opensCount;
	public SourceModuleBinding binding;
	public int declarationSourceStart;
	public int declarationSourceEnd;
	public int bodyStart;
	public int bodyEnd; // doesn't include the trailing comment if any.
	public int modifiersSourceStart;
	public ModuleScope scope;
	public char[][] tokens;
	public char[] moduleName;
	public long[] sourcePositions;
	public int modifiers = ClassFileConstants.AccDefault;
	boolean ignoreFurtherInvestigation;
	boolean hasResolvedModuleDirectives;
	boolean hasResolvedPackageDirectives;
	boolean hasResolvedTypeDirectives;
	CompilationResult compilationResult;

	public ModuleDeclaration(CompilationResult compilationResult, char[][] tokens, long[] positions) {
		this.compilationResult = compilationResult;
		this.exportsCount = 0;
		this.requiresCount = 0;
		this.tokens = tokens;
		this.moduleName = CharOperation.concatWith(tokens, '.');
		this.sourcePositions = positions;
		this.sourceEnd = (int) (positions[positions.length-1] & 0x00000000FFFFFFFF);
		this.sourceStart = (int) (positions[0] >>> 32);
	}

	public ModuleBinding setBinding(SourceModuleBinding sourceModuleBinding) {
		this.binding = sourceModuleBinding;
		return sourceModuleBinding;
	}

	public void checkAndSetModifiers() {
		int realModifiers = this.modifiers & ExtraCompilerModifiers.AccJustFlag;
		int expectedModifiers = ClassFileConstants.ACC_OPEN | ClassFileConstants.ACC_SYNTHETIC;
		if ((realModifiers & ~(expectedModifiers)) != 0) {
			this.scope.problemReporter().illegalModifierForModule(this);
			realModifiers &= expectedModifiers;
		}
		int effectiveModifiers = ClassFileConstants.AccModule | realModifiers;
		this.modifiers = this.binding.modifiers = effectiveModifiers;
	}

	public boolean isOpen() {
		return (this.modifiers & ClassFileConstants.ACC_OPEN) != 0;
	}

	public void createScope(final Scope parentScope) {
		this.scope = new ModuleScope(parentScope, this);
	}

	public void generateCode() {
		if ((this.bits & ASTNode.HasBeenGenerated) != 0)
			return;
		this.bits |= ASTNode.HasBeenGenerated;
		if (this.ignoreFurtherInvestigation) {
			return;
		}
		try {
			// create the result for a compiled type
			LookupEnvironment env = this.scope.environment();
			ClassFile classFile = env.classFilePool.acquireForModule(this.binding, env.globalOptions);
			classFile.initializeForModule(this.binding);

			// finalize the compiled type result
			classFile.addModuleAttributes(this.binding, this.annotations, this.scope.referenceCompilationUnit());
			this.scope.referenceCompilationUnit().compilationResult.record(
				this.binding.moduleName,
				classFile);
		} catch (AbortType e) {
			if (this.binding == null)
				return;
		}
	}

	/** Resolve those module directives that relate to modules (requires). */
	public void resolveModuleDirectives(CompilationUnitScope cuScope) {
		if (this.binding == null) {
			this.ignoreFurtherInvestigation = true;
			return;
		}
		if (this.hasResolvedModuleDirectives)
			return;

		this.hasResolvedModuleDirectives = true;

		Set requiredModules = new HashSet<>();
		Set requiredTransitiveModules = new HashSet<>();
		for(int i = 0; i < this.requiresCount; i++) {
			RequiresStatement ref = this.requires[i];
			if (ref != null && ref.resolve(cuScope) != null) {
				if (!requiredModules.add(ref.resolvedBinding)) {
					cuScope.problemReporter().duplicateModuleReference(IProblem.DuplicateRequires, ref.module);
				}
				if (ref.isTransitive())
					requiredTransitiveModules.add(ref.resolvedBinding);
				Collection deps = ref.resolvedBinding.dependencyGraphCollector().get();
				if (deps.contains(this.binding)) {
					cuScope.problemReporter().cyclicModuleDependency(this.binding, ref.module);
					requiredModules.remove(ref.module.binding);
				}
			}
		}
		this.binding.setRequires(requiredModules.toArray(new ModuleBinding[requiredModules.size()]),
								 requiredTransitiveModules.toArray(new ModuleBinding[requiredTransitiveModules.size()]));

		// also resolve module references inside package statements ("to"):
		if (this.exports != null) {
			for (ExportsStatement exportsStatement : this.exports) {
				if (exportsStatement.isQualified()) {
					for (ModuleReference moduleReference : exportsStatement.targets)
						moduleReference.resolve(cuScope);
				}
			}
		}
		if (this.opens != null) {
			for (OpensStatement opensStatement : this.opens) {
				if (opensStatement.isQualified()) {
					for (ModuleReference moduleReference : opensStatement.targets)
						moduleReference.resolve(cuScope);
				}
			}
		}
	}

	/** Resolve those module directives that relate to packages (exports, opens). */
	public void resolvePackageDirectives(CompilationUnitScope cuScope) {
		if (this.binding == null) {
			this.ignoreFurtherInvestigation = true;
			return;
		}
		if (this.hasResolvedPackageDirectives)
			return;

		this.hasResolvedPackageDirectives = true;

		Set exportedPkgs = new HashSet<>();
		for (int i = 0; i < this.exportsCount; i++) {
			ExportsStatement ref = this.exports[i];
 			if (ref != null && ref.resolve(cuScope)) {
				if (!exportedPkgs.add(ref.resolvedPackage)) {
					cuScope.problemReporter().invalidPackageReference(IProblem.DuplicateExports, ref);
				}
				char[][] targets = null;
				if (ref.targets != null) {
					targets = new char[ref.targets.length][];
					for (int j = 0; j < targets.length; j++)
						targets[j] = ref.targets[j].moduleName;
				}
				this.binding.addResolvedExport(ref.resolvedPackage, targets);
			}
		}

		HashtableOfObject openedPkgs = new HashtableOfObject();
		for (int i = 0; i < this.opensCount; i++) {
			OpensStatement ref = this.opens[i];
			if (isOpen()) {
				cuScope.problemReporter().invalidOpensStatement(ref, this);
			} else {
				if (openedPkgs.containsKey(ref.pkgName)) {
					cuScope.problemReporter().invalidPackageReference(IProblem.DuplicateOpens, ref);
				} else {
					openedPkgs.put(ref.pkgName, ref);
					ref.resolve(cuScope);
				}
				char[][] targets = null;
				if (ref.targets != null) {
					targets = new char[ref.targets.length][];
					for (int j = 0; j < targets.length; j++)
						targets[j] = ref.targets[j].moduleName;
				}
				this.binding.addResolvedOpens(ref.resolvedPackage, targets);
			}
		}
	}

	/** Resolve those module directives that relate to types (provides / uses). */
	public void resolveTypeDirectives(CompilationUnitScope cuScope) {
		if (this.binding == null) {
			this.ignoreFurtherInvestigation = true;
			return;
		}
		if (this.hasResolvedTypeDirectives)
			return;

		this.hasResolvedTypeDirectives = true;
		ASTNode.resolveAnnotations(this.scope, this.annotations, this.binding);

		Set allTypes = new HashSet<>();
		for(int i = 0; i < this.usesCount; i++) {
			TypeBinding serviceBinding = this.uses[i].serviceInterface.resolveType(this.scope);
			if (serviceBinding != null && serviceBinding.isValidBinding()) {
				if (!(serviceBinding.isClass() || serviceBinding.isInterface() || serviceBinding.isAnnotationType())) {
					cuScope.problemReporter().invalidServiceRef(IProblem.InvalidServiceIntfType, this.uses[i].serviceInterface);
				}
				if (!allTypes.add(this.uses[i].serviceInterface.resolvedType)) {
					cuScope.problemReporter().duplicateTypeReference(IProblem.DuplicateUses, this.uses[i].serviceInterface);
				}
			}
		}
		this.binding.setUses(allTypes.toArray(new TypeBinding[allTypes.size()]));

		Set interfaces = new HashSet<>();
		for(int i = 0; i < this.servicesCount; i++) {
			this.services[i].resolve(this.scope);
			TypeBinding infBinding = this.services[i].serviceInterface.resolvedType;
			if (infBinding != null && infBinding.isValidBinding()) {
				if (!interfaces.add(this.services[i].serviceInterface.resolvedType)) {
					cuScope.problemReporter().duplicateTypeReference(IProblem.DuplicateServices,
							this.services[i].serviceInterface);
				}
				this.binding.setImplementations(infBinding, this.services[i].getResolvedImplementations());
			}
		}
		this.binding.setServices(interfaces.toArray(new TypeBinding[interfaces.size()]));
	}

	public void analyseCode(CompilationUnitScope skope) {
		analyseModuleGraph(skope);
		analyseReferencedPackages(skope);
	}

	private void analyseReferencedPackages(CompilationUnitScope skope) {
		if (this.exports != null) {
			analyseSomeReferencedPackages(this.exports, skope);
		}
		if (this.opens != null) {
			analyseSomeReferencedPackages(this.opens, skope);
		}
	}

	private void analyseSomeReferencedPackages(PackageVisibilityStatement[] stats, CompilationUnitScope skope) {
		for (PackageVisibilityStatement stat : stats) {
			PlainPackageBinding pb = stat.resolvedPackage;
			if (pb == null)
				continue;
			if (pb.hasCompilationUnit(true))
				continue;
			for (ModuleBinding req : this.binding.getAllRequiredModules()) {
				for (PlainPackageBinding exported : req.getExports()) {
					if (CharOperation.equals(pb.compoundName, exported.compoundName)) {
						skope.problemReporter().exportingForeignPackage(stat, req);
						return;
					}
				}
			}
			skope.problemReporter().invalidPackageReference(IProblem.PackageDoesNotExistOrIsEmpty, stat);
		}
	}

	public void analyseModuleGraph(CompilationUnitScope skope) {
		if (this.requires != null) {
			// collect transitively:
			Map> pack2mods = new HashMap<>();
			for (ModuleBinding requiredModule : this.binding.getAllRequiredModules()) {
				for (PlainPackageBinding exportedPackage : requiredModule.getExports()) {
					if (this.binding.canAccess(exportedPackage)) {
						String packName = String.valueOf(exportedPackage.readableName());
						Set mods = pack2mods.get(packName);
						if (mods == null)
							pack2mods.put(packName, mods = new HashSet<>());
						mods.add(requiredModule);
					}
				}
			}
			// report against the causing requires directives:
			for (RequiresStatement requiresStat : this.requires) {
				ModuleBinding requiredModule = requiresStat.resolvedBinding;
				if (requiredModule != null) {
					if (requiredModule.isDeprecated())
						skope.problemReporter().deprecatedModule(requiresStat.module, requiredModule);
					analyseOneDependency(requiresStat, requiredModule, skope, pack2mods);
					if (requiresStat.isTransitive()) {
						for (ModuleBinding secondLevelModule : requiredModule.getAllRequiredModules())
							analyseOneDependency(requiresStat, secondLevelModule, skope, pack2mods);
					}
				}
			}
		}
	}

	private void analyseOneDependency(RequiresStatement requiresStat, ModuleBinding requiredModule, CompilationUnitScope skope,
			Map> pack2mods)
	{
		for (PlainPackageBinding pack : requiredModule.getExports()) {
			Set mods = pack2mods.get(String.valueOf(pack.readableName()));
			if (mods != null && mods.size() > 1) {
				CompilerOptions compilerOptions = skope.compilerOptions();
				boolean inJdtDebugCompileMode = compilerOptions.enableJdtDebugCompileMode;
				if (!inJdtDebugCompileMode) {
					skope.problemReporter().conflictingPackagesFromModules(pack, mods, requiresStat.sourceStart, requiresStat.sourceEnd);
				}
			}
		}
	}

	public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope) {
		visitor.visit(this, unitScope);
	}

	public StringBuilder printHeader(int indent, StringBuilder output) {
		if (this.annotations != null) {
			for (int i = 0; i < this.annotations.length; i++) {
				this.annotations[i].print(indent, output);
				if (i != this.annotations.length - 1)
					output.append(" "); //$NON-NLS-1$
			}
			output.append('\n');
		}
		if (isOpen()) {
			output.append("open "); //$NON-NLS-1$
		}
		output.append("module "); //$NON-NLS-1$
		output.append(CharOperation.charToString(this.moduleName));
		return output;
	}
	public StringBuilder printBody(int indent, StringBuilder output) {
		output.append(" {"); //$NON-NLS-1$
		if (this.requires != null) {
			for(int i = 0; i < this.requiresCount; i++) {
				output.append('\n');
				printIndent(indent + 1, output);
				this.requires[i].print(0, output);
			}
		}
		if (this.exports != null) {
			for(int i = 0; i < this.exportsCount; i++) {
				output.append('\n');
				this.exports[i].print(indent + 1, output);
			}
		}
		if (this.opens != null) {
			for(int i = 0; i < this.opensCount; i++) {
				output.append('\n');
				this.opens[i].print(indent + 1, output);
			}
		}
		if (this.uses != null) {
			for(int i = 0; i < this.usesCount; i++) {
				output.append('\n');
				this.uses[i].print(indent + 1, output);
			}
		}
		if (this.servicesCount != 0) {
			for(int i = 0; i < this.servicesCount; i++) {
				output.append('\n');
				this.services[i].print(indent + 1, output);
			}
		}
		output.append('\n');
		return printIndent(indent, output).append('}');
	}

	@Override
	public StringBuilder print(int indent, StringBuilder output) {
		//
		printIndent(indent, output);
		printHeader(0, output);
		return printBody(indent, output);
	}

	@Override
	public void abort(int abortLevel, CategorizedProblem problem) {
		switch (abortLevel) {
			case AbortCompilation :
				throw new AbortCompilation(this.compilationResult, problem);
			case AbortCompilationUnit :
				throw new AbortCompilationUnit(this.compilationResult, problem);
			case AbortMethod :
				throw new AbortMethod(this.compilationResult, problem);
			default :
				throw new AbortType(this.compilationResult, problem);
		}
	}

	@Override
	public CompilationResult compilationResult() {
		return this.compilationResult;
	}

	@Override
	public CompilationUnitDeclaration getCompilationUnitDeclaration() {
		return this.scope.referenceCompilationUnit();
	}

	@Override
	public boolean hasErrors() {
		return this.ignoreFurtherInvestigation;
	}

	@Override
	public void tagAsHavingErrors() {
		this.ignoreFurtherInvestigation = true;
	}

	@Override
	public void tagAsHavingIgnoredMandatoryErrors(int problemId) {
		// Nothing to do for this context;
	}

	public String getModuleVersion() {
		if (this.scope != null) {
			LookupEnvironment env = this.scope.environment().root;
			return env.moduleVersion;
		}
		return null;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy