关于类的符号输入过程第二篇

 

在第一阶段将未处理完的ClassSymbol放入uncompleted队列后,循环队列中的ClassSymbol并调用complete()方法,从而调用了MemberEnter类的complete(Symbol symbol)方法。

在这个类中主要对ClassSymbol中的ClassType进行了属性的填充,不过也会有其它的一些逻辑。

 

1、访问MemberEnter类的visitTopLevel(JCCompilationUnit jcCompilationUnit):

 

public void visitTopLevel(JCCompilationUnit jcCompilationUnit) {
        // 如果运行完importAll()方法后,那么starImportScope中的elements就不为null
        if (jcCompilationUnit.starImportScope.elements != null) { // starImportScope为A scope for all import-on-demands.
            // we must have already processed this toplevel
            return;
        }

        // check that no class exists with same fully qualified name as toplevel package
        if (checkClash && jcCompilationUnit.packageIdentifier != null) {
            Symbol packageSymbol = jcCompilationUnit.packageSymbol;
			while (packageSymbol.ownerSymbol != symbolTable.rootPackage) { // 进行循环检测
				packageSymbol.ownerSymbol.complete(); // enter all class members of packageSymbol
				if (symbolTable.classes.get(packageSymbol.getQualifiedName()) != null) {
					log.error(jcCompilationUnit.position, "pkg.clashes.with.class.of.same.name", packageSymbol); // 程序包{0}与带有相同名称的类冲突
                }
				packageSymbol = packageSymbol.ownerSymbol;
			}
        }

        // process package annotations
        annotateLater(jcCompilationUnit.packageAnnotations, environment, jcCompilationUnit.packageSymbol);

        // Import-on-demand java.lang.
        PackageSymbol pkgSymbol = classReader.enterPackage(names.java_lang);
        importAll(jcCompilationUnit.position, pkgSymbol , environment);

        // Process all import clauses. jcCompilationUnit.defs中包含JCImport也包含JCClassDecl
        memberEnter(jcCompilationUnit.defs, environment);
    }

重点来查看importAll()方法的逻辑。

 

2、调用importAll()方法后,会将PackageSymbol中members_field中存储的所有符号(java.lang包下定义的类符号)导入到当前environment.toplevel.starImportScope中。

调用importAll()方法,这个方法的具体代码如下:

 

private void importAll( int position,
                              final TypeSymbol typeSymbol,
                              Environment<AttrContext> environment) {
		// Check that packages imported from exist (JLS ???).
		if (  typeSymbol.kind == _PCK_1 &&
              typeSymbol.members().elements == null && // PackageSymbol的members()方法中还会调用ClassReader的complete()方法
              !typeSymbol.exists() // PackageSymbol中的exists()方法 (flags_field & EXISTS) != 0
        ){
			// If we can't find java.lang, exit immediately.
			if (((PackageSymbol)typeSymbol).fullname.equals(names.java_lang)) {
				JCDiagnostic msg = diags.fragment("fatal.err.no.java.lang"); // 致命错误: 在类路径或引导类路径中找不到程序包 java.lang
                throw new FatalError(msg);
			} else {
				log.error(DiagnosticFlag.RESOLVE_ERROR, position, "doesnt.exist", typeSymbol); // 程序包{0}不存在
            }
		}
        Scope membersField = typeSymbol.members();
		environment.toplevel.starImportScope.importAll(membersField);
	}

调用typeSymbol.members()方法会触发了java.lang名称的PackageSymbol的complete()方法,complete()方法主要调用ClassReader方法来完成主要逻辑,代码如下:

 

/**
	 * Completion for classes to be loaded. Before a class is loaded we make
	 * sure its enclosing class (if any 如果有的话) is loaded.
	 * 
	 * 在完成类 将被加载之前,要确保它的封闭类已经被加载了
	 */
	public void complete(Symbol symbol) throws CompletionFailure {
		if (symbol.kind == _TYP_2) {
			ClassSymbol classSymbol = (ClassSymbol) symbol;
			classSymbol.members_field = new ErrorScope(classSymbol); // make sure it's always defined
			boolean saveSuppressFlush = suppressFlush;
			suppressFlush = true;
			try {
				completeOwners(classSymbol.owner);
				completeEnclosing(classSymbol);
			} finally {
				suppressFlush = saveSuppressFlush;
			}
			fillIn(classSymbol);
		} else if (symbol.kind == _PCK_1) {
			PackageSymbol packageSymbol = (PackageSymbol) symbol;
			try {
				fillIn(packageSymbol); // 为这个符号填充一些信息,如members_field,并且为Scope中的Entry添加符号
			} catch (IOException ex) {
				throw new CompletionFailure(symbol, ex.getLocalizedMessage()).initCause(ex);
			}
		}
		if (!filling && !suppressFlush) {
			annotate.flush(); // finish attaching annotations
		}
	}

 
(1)symbol.kind=_TYP_2的逻辑,主要调用了两个方法完成classSymbol的处理。

/** complete up through the enclosing package. */
	private void completeOwners(Symbol ownerSymbol) {
		if (ownerSymbol.kind != _PCK_1) { // 处理的是非PackageSymbol
			completeOwners(ownerSymbol.owner); // 递归调用
		}
		ownerSymbol.complete(); 
	}

  

/**
	 * Tries to complete lexically enclosing classes if classSymbol looks like a
	 * nested class. This is similar to completeOwners but handles the situation
	 * when a nested class is accessed directly as it is possible with the Tree
	 * API or javax.lang.model.*.
	 */
	private void completeEnclosing(ClassSymbol classSymbol) {
		if (classSymbol.owner.kind != _PCK_1) { // 处理的是PackageSymbol
			return;
		}

		Symbol owner = classSymbol.owner;
		Name shortName = Convert.shortName(classSymbol.name);

		List<Name> names = Convert.enclosingCandidates(shortName);

		for (Name name : names) {
			Symbol enclosingClass = owner.members().lookup(name).symbol;
			if (enclosingClass == null) {
				enclosingClass = classes.get(TypeSymbol.formFlatName(name, owner));
			}
			if (enclosingClass != null) {
				enclosingClass.complete();
			}
		}
	}

调用完如上的两个方法后继承调用fillIn()方法,代码如下:

/**
	 * Fill in definition of class `c' from corresponding class or source file.
	 */
	private void fillIn(ClassSymbol classSymbol) {
		if (completionFailureName == classSymbol.fullname) {
			throw new CompletionFailure(classSymbol, "user-selected completion failure by class name");
		}
		currentOwner = classSymbol;
		warnedAttrs.clear();
		JavaFileObject classfile = classSymbol.classfile;
		if (classfile != null) {
			JavaFileObject previousClassFile = currentClassFile;
			try {
				if (filling) {
					Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
				}
				currentClassFile = classfile;
				if (verbose) {
					log.printVerbose("loading", currentClassFile.toString());
				}
				if (sourceCompleter != null) {
					sourceCompleter.complete(classSymbol);
				} else {
					throw new IllegalStateException("Source completer required to read " + classfile.toUri());
				}
				return;
			} finally {
				currentClassFile = previousClassFile;
			}
		} else {
			JCDiagnostic diag = diagFactory.fragment("class.file.not.found", classSymbol.flatname);
			throw newCompletionFailure(classSymbol, diag);
		}
	}

ClassReader中定义了一个接口,如下:

public interface SourceCompleter {
		void complete(ClassSymbol sym) throws CompletionFailure;
	}  

其实现类只有一个JavaCompiler,如下:

  /** Complete compiling a source file that has been accessed
     *  by the class file reader.
     *  @param c          The class the source file of which needs to be compiled.
     *  @param filename   The name of the source file.
     *  @param f          An input stream that reads the source file.
     */
    public void complete(ClassSymbol c) throws CompletionFailure {
//      System.err.println("completing " + c);//DEBUG
        if (completionFailureName == c.fullname) {
            throw new CompletionFailure(c, "user-selected completion failure by class name");
        }
        JCCompilationUnit tree;
        JavaFileObject filename = c.classfile;
        JavaFileObject prev = log.useSource(filename);

        try {
            tree = parse(filename, filename.getCharContent(false));
        } catch (IOException e) {
            log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
            tree = make.TopLevel(List.<JCAnnotation>nil(), null, List.<JCTree>nil());
        } finally {
            log.useSource(prev);
        }

        enter.complete(List.of(tree), c);

        if (enter.getEnvironment(c) == null) {
            boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE);
            if (isPkgInfo) {
                if (enter.getEnvironment(tree.packageSymbol) == null) {
					JCDiagnostic diag = diagFactory.fragment("file.does.not.contain.package", c.location());
                    throw reader.new BadClassFile(c, filename, diag);
                }
            } else {
				JCDiagnostic diag = diagFactory.fragment("file.doesnt.contain.class", c.getQualifiedName());
                throw reader.new BadClassFile(c, filename, diag);
            }
        }

        implicitSourceFilesRead = true;
    }

  

 

(2)symbol.kind=_PCK_1的逻辑,主要调用了fillIn()方法,主要就是往packageSymbol的members_field属性(Scope类型)中填充java.lang包下的所有类符号ClassSymbol,具体代码实现如下:  

 

/**
	 * Load directory of package into members scope.
	 */
	private void fillIn(PackageSymbol packageSymbol) throws IOException {
		if (packageSymbol.members_field == null) {
			packageSymbol.members_field = new Scope(packageSymbol);
		}
		String packageName = packageSymbol.fullname.toString();

		Set<JavaFileObject.Kind> kinds = getPackageFileKinds();

		// Lists all file objects matching the given criteria in the given location.
		// List file objects in "subpackages" if recurse is true.
		if (packageName == null || EnumSet.of(JavaFileObject.Kind.CLASS) == null || fileManager == null) {
			return;
		}
		Iterable<JavaFileObject> files = fileManager.list(PLATFORM_CLASS_PATH, packageName,
				EnumSet.of(JavaFileObject.Kind.CLASS), false);

		/**
		 * Location to search for platform classes. Sometimes called the boot
		 * class path.
		 */
		fillIn(packageSymbol, PLATFORM_CLASS_PATH, files);

		Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds);
		classKinds.remove(JavaFileObject.Kind.SOURCE);
		boolean wantClassFiles = !classKinds.isEmpty();

		Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds);
		sourceKinds.remove(JavaFileObject.Kind.CLASS);
		boolean wantSourceFiles = !sourceKinds.isEmpty();
		/**
		 * Location to search for existing source files.
		 */
		boolean haveSourcePath = fileManager.hasLocation(SOURCE_PATH);

		// 省略一部分代码
	}

又调用了fillIn()私有方法,代码如下:

private void fillIn(PackageSymbol packageSymbol, Location location, Iterable<JavaFileObject> files) {
		currentLoc = location;
		for (JavaFileObject javaFileObject : files) {
			switch (javaFileObject.getKind()) {
				case CLASS:
				case SOURCE: {
					// TODO pass binaryName to includeClassFile
					String binaryName = fileManager.inferBinaryName(currentLoc, javaFileObject);
					String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
					if (SourceVersion.isIdentifier(simpleName) || simpleName.equals("package-info")) { // simpleName不为java定义的关键字或者不为package-info时
						includeClassFile(packageSymbol, javaFileObject);
					}
					break;
				}
				default: {
					extraFileActions(packageSymbol, javaFileObject);
				}
			}
		}
	}

调用includeClassFile()方法,具体代码如下:

/**
	 * Include class corresponding to given class file in package, unless (1) we
	 * already have one the same kind (.class or .java), or (2) we have one of
	 * the other kind, and the given class file is older.
	 */
	protected void includeClassFile(PackageSymbol packageSymbol, JavaFileObject file) {
		if ((packageSymbol.flags_field & EXISTS) == 0) {
			for (Symbol q = packageSymbol; q != null && q.kind == _PCK_1; q = q.owner) {
				q.flags_field |= EXISTS;
			}
		}
		JavaFileObject.Kind kind = file.getKind();
		int seen;
		if (kind == JavaFileObject.Kind.CLASS) {
			seen = CLASS_SEEN;
		} else {
			seen = SOURCE_SEEN;
		}
		String binaryName = fileManager.inferBinaryName(currentLoc, file);
		int lastDot = binaryName.lastIndexOf(".");
		Name classname = names.fromString(binaryName.substring(lastDot + 1));

		boolean isPkgInfo = (classname == names.package_info);
		ClassSymbol classSymbol = null;
		if (isPkgInfo) {
			classSymbol = packageSymbol.package_info;
		} else {
			Entry entry = packageSymbol.members_field.lookup(classname);
			classSymbol = (ClassSymbol) entry.symbol;
		}

		if (classSymbol == null) {
			classSymbol = enterClass(classname, packageSymbol);

			if (classSymbol.classfile == null) { // only update the file if's it's newly created
				classSymbol.classfile = file;
			}

			if (isPkgInfo) {
				packageSymbol.package_info = classSymbol;
			} else {
				if (classSymbol.owner == packageSymbol) { // it might be an inner class
					packageSymbol.members_field.enter(classSymbol);
				}
			}

		} else if (classSymbol.classfile != null && (classSymbol.flags_field & seen) == 0) {
			// if c.classfile == null, we are currently compiling this class and
			// no further action is necessary.
			// if (c.flags_field & seen) != 0, we have already encountered a
			// file of the same kind; again no further action is necessary.
			if ((classSymbol.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0) {
				classSymbol.classfile = preferredFileObject(file, classSymbol.classfile);
			}
		}
		classSymbol.flags_field |= seen;
	}

创建file对应的类符号并且输入到packageSymbol的members_field属性中。同时也填充了classSymbol的classfile、flags_field属性。如有必要,需要调用enterClass()方法来完成对classSymbol的创建。

enterClass()方法如下:

/**
	 * Create a new toplevel or member class symbol with given name and owner
	 * and enter in `classes' unless already there.
	 */
	public ClassSymbol enterClass(Name name, TypeSymbol ownerTypeSymbol) {

		Name flatName = TypeSymbol.formFlatName(name, ownerTypeSymbol);
		ClassSymbol classSymbol = classes.get(flatName);
		if (classSymbol == null) {
			classSymbol = defineClass(name, ownerTypeSymbol);
			classes.put(flatName, classSymbol);
		} else {
			boolean a = (classSymbol.name != name || classSymbol.owner != ownerTypeSymbol);
			boolean b = ownerTypeSymbol.kind == _TYP_2;
			boolean c = classSymbol.owner.kind == _PCK_1;
			if (a && b && c) {
				// reassign fields of classes that might have been loaded with
				// their flat names.
				// TODO 为什么要提前通过类全名进行加载呢?
				classSymbol.owner.members().remove(classSymbol);
				classSymbol.name = name;
				classSymbol.owner = ownerTypeSymbol;
				classSymbol.fullname = ClassSymbol.formFullName(name, ownerTypeSymbol);
			}
		}
		return classSymbol;
	}

defineClass()方法代码如下:

/**
	 * Define a new class given its name and owner.
	 */
	public ClassSymbol defineClass(Name name, Symbol owner) {
		ClassSymbol c = new ClassSymbol(0, name, owner);
		if (owner.kind == _PCK_1) {
			Assert.checkNull(classes.get(c.flatname), c);
		}
		c.completer = this; // 将ClassReader对象赋值给新的ClassSymbol的completer属性
		return c;
	}

 

调用之前与这后的截图如下:

在执行过某个Symbol的complete()方法后,其中的属性completer会被置为null。而调用某个符号Symbol的complete()方法也主要是对members_field进行符号的填充。只有TypeSymbol,也就是PackageSymbol与ClassSymbol有members_field属性。

 

 

3、调用memberEnter()方法后处理JCImport语法节点。查看MemberEnter类的visitImport()方法,最重要的逻辑如下: 

 

 // process the non-static imports and the static imports of types. 处理类型的静态和非静态引入
    public void visitImport(JCImport jcImport) {

        JCTree jcTree = jcImport.qualified;
        Name name = TreeInfo.name(jcTree); // identifier/field/a parameterized type
        TypeSymbol typeSymbol;

        // Create a local environment pointing to this tree to disable
        // effects of other imports in Resolve.findGlobalType
        Environment<AttrContext> localEnvironment = environment.duplicate(jcImport); // 更新tree属性为JCImport

        // Attribute qualifying package or class.
        JCFieldAccess jcFieldAccess = (JCFieldAccess) jcTree;

        int protoKind;
        if(jcImport.staticImport){
            // import static java.lang.Math.*;
            // import static java.lang.Math.sin;
            protoKind = _TYP;
        }else{
            // import java.lang.* _PCK
            // import java.lang.Object _TYP
            protoKind = _TYP | _PCK;
        }

        // 在符号输入的过程中也可能进行标记,如下:
        Type type = attr.attribTree(jcFieldAccess.selected, localEnvironment, protoKind, Type.noType);
        typeSymbol = type.typeSymbol;

        if (name == names.asterisk) {
            // Import on demand.
            check.checkCanonical(jcFieldAccess.selected);
            if (jcImport.staticImport){
            	 importStaticAll(jcImport.position, typeSymbol, environment);
            }else{
            	 importAll(jcImport.position, typeSymbol, environment);
            }
        } else {
            // Named type import.
            if (jcImport.staticImport) {
                importNamedStatic(jcImport.position(), typeSymbol, name, localEnvironment);
                check.checkCanonical(jcFieldAccess.selected);
            } else {
                Type type1 = attributeImportType(jcTree, localEnvironment);
                TypeSymbol typeSymbol1 = type1.typeSymbol;
                check.checkCanonical(jcTree); // 是否是合乎规范的?
                importNamed(jcImport.position(), typeSymbol1, environment); // Import given class.
            }
        }
    }

如上代码要处理import java.util.ArrayList;语句。

(1)标记java.util,获取PackageType与typeSymbol,如下截图。

(2)处理java.util.ArrayList,也就是调用attributeImportType()方法,返回ClassType类型

(3)调用importNamed()方法为当前环境的Scope中导入符号。

 

4、对于JCClassDefinition节点调用MemberEnter的visitTree()后不做任何处理。但是在MemberEnter的complete(Symbol symbol)方法中对JCClassDefinition语法节点进行填充。

 

(1) 填充classType属性的supertype_field属性

Type superType = null;
            if(jcClassDeclaration.extending != null){
                superType = attr.attribBase(jcClassDeclaration.extending, baseEnvironment, true, false, true);
            }else{
                if( (jcClassDeclaration.modifiers.flags & Flags.ENUM) != 0 && !target.compilerBootstrap(classSymbol) ){
                    JCExpression jcExpression = enumBase(jcClassDeclaration.position, classSymbol);
                    superType = attr.attribBase(jcExpression, baseEnvironment,true, false, false);
                }else{
                    if(classSymbol.fullname == names.java_lang_Object){
                        superType = Type.noType;
                    }else{
                        superType = symbolTable.objectType;
                    }
                }
            }

如果使用了extends关键字来明确继承一个类,如继承Thead类时,其superType如下截图。

(2) 填充classType属性的interfaces_field和all_interfaces_field属性

// Determine interfaces.
            ListBuffer<Type> interfaces = new ListBuffer<Type>();
            ListBuffer<Type> all_interfaces = null; // lazy initializer
            Set<Type> interfaceSet = new HashSet<Type>();
            List<JCExpression> interfaceTrees = jcClassDeclaration.implementing;

            // 为枚举类型添加了两个接口,Comparable和Serializable
            if ((jcClassDeclaration.modifiers.flags & Flags.ENUM) != 0 && target.compilerBootstrap(classSymbol)) {
                // add interface Comparable<T>
                // ClassType(Type outer, List<Type> typeParameters, TypeSymbol typeSymbol)
                ClassType ct =  new ClassType(
                        symbolTable.comparableType.getEnclosingType(), // java.lang.Comparable
                        List.of(classSymbol.type),
                        symbolTable.comparableType.typeSymbol
                );
                JCExpression jcExpression = treeMaker.Type(ct);
                interfaceTrees = interfaceTrees.prepend(jcExpression);
                // add interface Serializable
                JCExpression serializableExpr = treeMaker.Type(symbolTable.serializableType);
                interfaceTrees =  interfaceTrees.prepend(serializableExpr);
            }

            for (JCExpression iface : interfaceTrees) {
                Type interfaceType = attr.attribBase(iface, baseEnvironment, false, true, true);
                if (interfaceType.typeTag == CLASS) {
                    interfaces.append(interfaceType);
                    if (all_interfaces != null){
                    	 all_interfaces.append(interfaceType);
                    }
                    check.checkNotRepeated(iface.position(), types.erasure(interfaceType), interfaceSet);
                } else { // 如果进入这个循环,可能已经出错了?
                    if (all_interfaces == null){
                        all_interfaces = new ListBuffer<Type>().appendList(interfaces);
                    }
                    all_interfaces.append(modelMissingTypes(interfaceType, iface, true));
                }
            }

            // 处理annotation注解
            // java.lang.annotation.Annotation
            if ( (classSymbol.flags_field & ANNOTATION) != 0 ) {
                 classType.interfaces_field = List.of(symbolTable.annotationType);
                 classType.all_interfaces_field = classType.interfaces_field;
            }  else {
                 classType.interfaces_field = interfaces.toList();
                 classType.all_interfaces_field = (all_interfaces == null) ? classType.interfaces_field : all_interfaces.toList();
            }

            // 如果类是Object,则进一步其父类和接口
            if (classSymbol.fullname == names.java_lang_Object) {
                if (jcClassDeclaration.extending != null) {
					check.checkNonCyclic(jcClassDeclaration.extending.position(), superType);
                    classType.supertype_field = Type.noType;
                }
                else if (jcClassDeclaration.implementing.nonEmpty()) {
					check.checkNonCyclic(jcClassDeclaration.implementing.head.position(), classType.interfaces_field.head);
                    classType.interfaces_field = List.nil();
                }
            }

  

  

 (3) 标记类的类型变量

attr.attribTypeVariables(jcClassDeclaration.typeParameters, baseEnvironment);

 

(4) 添加默认的构造函数

 

// Add default constructorSymbol if needed.
            // 在非接口且没有默认构造函数的情况下,添加默认的构造函数
            if ((classSymbol.flags() & INTERFACE) == 0 &&  !TreeInfo.hasConstructors(jcClassDeclaration.defs)) {
            	
            	// 默认如下三项都为空
                List<Type> argumentTypes = List.nil();
                List<Type> typeParameters = List.nil();
                List<Type> thrown = List.nil();
                
                long ctorFlags = 0;
                boolean based = false;

                if (classSymbol.name.isEmpty()) { // 如果符号的name为空的话
                    JCNewClass jcNewClass = (JCNewClass)environment.next.tree;
                    if (jcNewClass.constructorSymbol != null) {
                        Type superConstructorType = types.memberType(classSymbol.type,jcNewClass.constructorSymbol);
                        argumentTypes = superConstructorType.getParameterTypes();
                        typeParameters = superConstructorType.getTypeArguments();
                        ctorFlags = jcNewClass.constructorSymbol.flags() & VARARGS;
                        if (jcNewClass.enclosingExpression != null) {
                            argumentTypes = argumentTypes.prepend(jcNewClass.enclosingExpression.type);
                            based = true;
                        }
                        thrown = superConstructorType.getThrownTypes();
                    }
                }
				JCTree constructorDef = DefaultConstructor(treeMaker.at(jcClassDeclaration.position), classSymbol, typeParameters, argumentTypes, thrown, ctorFlags,based);
                jcClassDeclaration.defs = jcClassDeclaration.defs.prepend(constructorDef);
            }

  

(5) 输入this与super关键字到当前的作用域

 

 // If this is a class, enter symbols for this and super into current scope.
            // 如果为一个类,输入this和super关键字到当前的作用域
            if ((classSymbol.flags_field & INTERFACE) == 0) {
                // 输入this符号
				VarSymbol thisSymbol = new VarSymbol(FINAL | HASINIT, names._this, classSymbol.type, classSymbol);
                thisSymbol.pos = Position.FIRSTPOS; // firstpos
                environment.info.scope.enter(thisSymbol);

                // 有直接的父类才会输入super符号???
                if (classType.supertype_field.typeTag == CLASS) { // 对于接口,supertype_field的typeTag为INTERFACE
					VarSymbol superSymbol = new VarSymbol(FINAL | HASINIT, names._super, classType.supertype_field, classSymbol);
                    superSymbol.pos = Position.FIRSTPOS;
                    environment.info.scope.enter(superSymbol);
                }
            }

  

 在complete()方法的结尾处有如下代码,是通过循环取出halfcompleted队列中的值来继承进行符号填充的。

  try {
            while (halfcompleted.nonEmpty()) {
                Environment<AttrContext> temp = halfcompleted.next();
                finish(temp);
            }
        } finally {
            isFirst = true;
        }

  

5、处理JCMethodDeclaration

如上的实例中有两个方法,一个为test方法,另外一个为编译器默认添加的构造方法<init>。

 

public void visitMethodDefinition(JCMethodDeclaration jcMethodDeclaration) {
        Scope enclosingScope = enter.enterScope(environment);
        // MethodSymbol(long flags, Name name, Type type, Symbol owner)
        MethodSymbol methodSymbol = new MethodSymbol(0, jcMethodDeclaration.name, null, enclosingScope.owner);
        // Check that given modifiers are legal for given symbol and
        // return modifiers together with any implicit modifiers for that symbol.
        // checkFlags(DiagnosticPosition pos, long flags, Symbol symbol, JCTree jcTree)
        methodSymbol.flags_field = check.checkFlags(jcMethodDeclaration.position(), jcMethodDeclaration.modifiers.flags, methodSymbol, jcMethodDeclaration);
        jcMethodDeclaration.methodSymbol = methodSymbol; // 为methodSymbol赋值

        Environment<AttrContext> localEnvironment = methodEnvironment(jcMethodDeclaration, environment);

        DeferredLintHandler prevLintHandler = check.setDeferredLintHandler(deferredLintHandler.setPos(jcMethodDeclaration.position()));
        try {
            // Compute the method type
			methodSymbol.type = signature(jcMethodDeclaration.typeParameters, jcMethodDeclaration.parameters,
                                          jcMethodDeclaration.returnType, jcMethodDeclaration.thrown, localEnvironment);
        } finally {
            check.setDeferredLintHandler(prevLintHandler);
        }

        // Set methodSymbol.parameters
        ListBuffer<VarSymbol> parameters = new ListBuffer<VarSymbol>();
        JCVariableDeclaration lastParameter = null;
        for (List<JCVariableDeclaration> l = jcMethodDeclaration.parameters; l.nonEmpty(); l = l.tail) {
            JCVariableDeclaration param = lastParameter = l.head;
            parameters.append(Assert.checkNonNull(param.varSymbol));
        }
        methodSymbol.parameters = parameters.toList();

        // mark the method varargs, if necessary
        if (lastParameter != null && (lastParameter.modifiers.flags & Flags.VARARGS) != 0){
        	  methodSymbol.flags_field |= Flags.VARARGS;
        }

        // method scope为什么要和class scope共享hashtable呢?
        localEnvironment.info.scope.leave(); // ??

        if (check.checkUnique(jcMethodDeclaration.position(), methodSymbol, enclosingScope)) {
            enclosingScope.enter(methodSymbol);
        }
        annotateLater(jcMethodDeclaration.modifiers.annotations, localEnvironment, methodSymbol);
        if (jcMethodDeclaration.defaultValue != null){ // 对于注解定义类中定义的方法可以有default默认值
            annotateDefaultValueLater(jcMethodDeclaration.defaultValue, localEnvironment, methodSymbol);
        }
    }

可以看到主要填充了JCMethodDeclaration的methodSymbol属性,并且对methodSymbol的flags_field、parameters、type等属性进行值进行了填充。  

 

6、JCVariableDeclaration语法节点

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

转载于:https://www.cnblogs.com/extjs4/p/6627643.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值