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

spoon.reflect.visitor.LexicalScopeScanner Maven / Gradle / Ivy

Go to download

Spoon is a tool for meta-programming, analysis and transformation of Java programs.

There is a newer version: 11.1.1-beta-14
Show newest version
/*
 * SPDX-License-Identifier: (MIT OR CECILL-C)
 *
 * Copyright (C) 2006-2023 INRIA and contributors
 *
 * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) or the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
 */
package spoon.reflect.visitor;

import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtCatch;
import spoon.reflect.code.CtLambda;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.declaration.CtAnnotationType;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtCompilationUnit;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtEnum;
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.CtMethod;

import java.lang.annotation.Annotation;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;

/**
 * A {@link CtScanner} which provides current lexical scope
 * of currently scanned AST node.
 */
public class LexicalScopeScanner extends EarlyTerminatingScanner {
	private final Deque scopes = new ArrayDeque<>();
	private final Map encounteredImportedQualifiedNames = new HashMap<>();

	protected void enter(spoon.reflect.declaration.CtElement e) {
		LexicalScope newFinder = onElement(scopes.peek(), e);
		if (newFinder != null) {
			scopes.push(newFinder);
		}
	}
	protected void exit(spoon.reflect.declaration.CtElement e) {
		LexicalScope topFinder = scopes.peek();
		if (topFinder != null && topFinder.getScopeElement() == e) {
			//we are living scope of this ConflictFinder. Pop it
			scopes.pop();
		}
	}
	private static NameScopeImpl EMPTY = new NameScopeImpl(null, null);
	/**
	 * @return {@link LexicalScope} of actually scanned element. The {@link LexicalScope#forEachElementByName(String, java.util.function.Function)} can be used
	 * to get all {@link CtElement}s which are mapped to that simple name
	 */
	public LexicalScope getCurrentLexicalScope() {
		LexicalScope ns = scopes.peek();
		return ns == null ? EMPTY : ns;
	}

	Map getEncounteredImportedQualifiedNames() {
		return encounteredImportedQualifiedNames;
	}

	/**
	 * Call it for each visited CtElement
	 * @param parent the parent ConflictFinder
	 * @param target an element
	 * @return new {@link NameScopeImpl} if `target` element declares new naming scope or null if there is no new scope
	 */
	private NameScopeImpl onElement(LexicalScope parent, CtElement target) {
		class Visitor extends CtAbstractVisitor {
			NameScopeImpl finder = null;
			@Override
			public void visitCtCompilationUnit(CtCompilationUnit compilationUnit) {
				//compilation unit items are added in TypeNameScope, because they depend on the inhertance hierarchy of the type itself
			}
			@Override
			public  void visitCtClass(CtClass ctClass) {
				finder = new TypeNameScope(parent, ctClass);
			}
			@Override
			public  void visitCtInterface(CtInterface intrface) {
				finder = new TypeNameScope(parent, intrface);
			}
			@Override
			public > void visitCtEnum(CtEnum ctEnum) {
				finder = new TypeNameScope(parent, ctEnum);
			}
			@Override
			public  void visitCtAnnotationType(CtAnnotationType annotationType) {
				finder = new TypeNameScope(parent, annotationType);
			}
			@Override
			public  void visitCtMethod(CtMethod m) {
				finder = new NameScopeImpl(parent, m, m.getParameters());
			}
			@Override
			public  void visitCtConstructor(CtConstructor c) {
				finder = new NameScopeImpl(parent, c, c.getParameters());
			}
			@Override
			public  void visitCtLambda(CtLambda lambda) {
				finder = new NameScopeImpl(parent, lambda, lambda.getParameters());
			}
			@Override
			public void visitCtCatch(CtCatch catchBlock) {
				finder = new NameScopeImpl(parent, catchBlock).addNamedElement(catchBlock.getParameter());
			}
			@Override
			public  void visitCtBlock(CtBlock block) {
				finder = new NameScopeImpl(parent, block);
			}
			@Override
			public  void visitCtLocalVariable(CtLocalVariable localVariable) {
				if (parent == null) {
					return;
				}
				parent.addNamedElement(localVariable);
			}
		};
		Visitor scanner = new Visitor();
		target.accept(scanner);
		return scanner.finder;
	}
}