// Copyright 2017 The Bazel Authors. All rights reserved. // // 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 com.google.devtools.skylark.skylint; import com.google.common.base.Preconditions; import com.google.devtools.build.lib.syntax.ASTNode; import com.google.devtools.build.lib.syntax.AbstractComprehension; import com.google.devtools.build.lib.syntax.AugmentedAssignmentStatement; import com.google.devtools.build.lib.syntax.BuildFileAST; import com.google.devtools.build.lib.syntax.DotExpression; import com.google.devtools.build.lib.syntax.Expression; import com.google.devtools.build.lib.syntax.FunctionDefStatement; import com.google.devtools.build.lib.syntax.Identifier; import com.google.devtools.build.lib.syntax.LValue; import com.google.devtools.build.lib.syntax.ListComprehension; import com.google.devtools.build.lib.syntax.ListLiteral; import com.google.devtools.build.lib.syntax.LoadStatement; import com.google.devtools.build.lib.syntax.Parameter; import com.google.devtools.build.lib.syntax.Statement; import com.google.devtools.build.lib.syntax.SyntaxTreeVisitor; import java.util.Collection; import java.util.Map; /** * AST visitor that keeps track of which symbols are in scope. * *
The methods {@code enterBlock}, {@code exitBlock}, {@code declare} and {@code reassign} can be
* overridden by a subclass to handle these "events" during AST traversal.
*/
public class AstVisitorWithNameResolution extends SyntaxTreeVisitor {
protected Environment env;
public AstVisitorWithNameResolution() {
this(Environment.defaultBazel());
}
public AstVisitorWithNameResolution(Environment env) {
this.env = env;
}
@Override
public void visit(BuildFileAST node) {
enterBlock();
// First process all global symbols ...
for (Statement stmt : node.getStatements()) {
if (stmt instanceof FunctionDefStatement) {
Identifier fun = ((FunctionDefStatement) stmt).getIdentifier();
env.addFunction(fun.getName(), fun);
declare(fun.getName(), fun);
} else {
visit(stmt);
}
}
// ... then check the functions
for (Statement stmt : node.getStatements()) {
if (stmt instanceof FunctionDefStatement) {
visit(stmt);
}
}
visitAll(node.getComments());
Preconditions.checkState(env.inGlobalBlock(), "didn't exit some blocks");
exitBlock();
}
@Override
public void visit(LoadStatement node) {
Map This method is there to be overridden in subclasses, it doesn't do anything by itself.
*
* @param name name of the variable declared
* @param node {@code ASTNode} where it was declared
*/
void declare(String name, ASTNode node) {}
/**
* Invoked when a variable is reassigned during AST traversal.
*
* This method is there to be overridden in subclasses, it doesn't do anything by itself.
*
* @param ident {@code Identifier} that was reassigned
*/
void reassign(Identifier ident) {}
/**
* Invoked when a variable is used during AST traversal.
*
* This method is there to be overridden in subclasses, it doesn't do anything by itself.
*
* @param ident {@code Identifier} that was reassigned
*/
void use(Identifier ident) {}
/**
* Invoked when a lexical block is entered during AST traversal.
*
* This method is there to be overridden in subclasses.
*/
void enterBlock() {
env.enterBlock();
}
/**
* Invoked when a lexical block is entered during AST traversal.
*
* This method is there to be overridden in subclasses.
*/
void exitBlock() {
env.exitBlock();
}
}