关于类的符号输入过程第二篇
?
在第一階段將未處理完的ClassSymbol放入uncompleted隊列后,循環(huán)隊列中的ClassSymbol并調(diào)用complete()方法,從而調(diào)用了MemberEnter類的complete(Symbol symbol)方法。
在這個類中主要對ClassSymbol中的ClassType進行了屬性的填充,不過也會有其它的一些邏輯。
?
1、訪問MemberEnter類的visitTopLevel(JCCompilationUnit jcCompilationUnit):
?
public void visitTopLevel(JCCompilationUnit jcCompilationUnit) {// 如果運行完importAll()方法后,那么starImportScope中的elements就不為nullif (jcCompilationUnit.starImportScope.elements != null) { // starImportScope為A scope for all import-on-demands.// we must have already processed this toplevelreturn;}// check that no class exists with same fully qualified name as toplevel packageif (checkClash && jcCompilationUnit.packageIdentifier != null) {Symbol packageSymbol = jcCompilationUnit.packageSymbol;while (packageSymbol.ownerSymbol != symbolTable.rootPackage) { // 進行循環(huán)檢測packageSymbol.ownerSymbol.complete(); // enter all class members of packageSymbolif (symbolTable.classes.get(packageSymbol.getQualifiedName()) != null) {log.error(jcCompilationUnit.position, "pkg.clashes.with.class.of.same.name", packageSymbol); // 程序包{0}與帶有相同名稱的類沖突}packageSymbol = packageSymbol.ownerSymbol;}}// process package annotationsannotateLater(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也包含JCClassDeclmemberEnter(jcCompilationUnit.defs, environment);}重點來查看importAll()方法的邏輯。
?
2、調(diào)用importAll()方法后,會將PackageSymbol中members_field中存儲的所有符號(java.lang包下定義的類符號)導(dǎo)入到當(dāng)前environment.toplevel.starImportScope中。
調(diào)用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()方法中還會調(diào)用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"); // 致命錯誤: 在類路徑或引導(dǎo)類路徑中找不到程序包 java.langthrow new FatalError(msg);} else {log.error(DiagnosticFlag.RESOLVE_ERROR, position, "doesnt.exist", typeSymbol); // 程序包{0}不存在}}Scope membersField = typeSymbol.members();environment.toplevel.starImportScope.importAll(membersField);}調(diào)用typeSymbol.members()方法會觸發(fā)了java.lang名稱的PackageSymbol的complete()方法,complete()方法主要調(diào)用ClassReader方法來完成主要邏輯,代碼如下:
?
/*** Completion for classes to be loaded. Before a class is loaded we make* sure its enclosing class (if any 如果有的話) is loaded.* * 在完成類 將被加載之前,要確保它的封閉類已經(jīng)被加載了*/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 definedboolean 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的邏輯,主要調(diào)用了兩個方法完成classSymbol的處理。
/*** 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) { // 處理的是PackageSymbolreturn;}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();}}}
調(diào)用完如上的兩個方法后繼承調(diào)用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;}其實現(xiàn)類只有一個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);//DEBUGif (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的邏輯,主要調(diào)用了fillIn()方法,主要就是往packageSymbol的members_field屬性(Scope類型)中填充java.lang包下的所有類符號ClassSymbol,具體代碼實現(xiàn)如下:
?
/*** 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);// 省略一部分代碼}又調(diào)用了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 includeClassFileString binaryName = fileManager.inferBinaryName(currentLoc, javaFileObject);String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);if (SourceVersion.isIdentifier(simpleName) || simpleName.equals("package-info")) { // simpleName不為java定義的關(guān)鍵字或者不為package-info時includeClassFile(packageSymbol, javaFileObject);}break;}default: {extraFileActions(packageSymbol, javaFileObject);}}}}調(diào)用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 createdclassSymbol.classfile = file;}if (isPkgInfo) {packageSymbol.package_info = classSymbol;} else {if (classSymbol.owner == packageSymbol) { // it might be an inner classpackageSymbol.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;}創(chuàng)建file對應(yīng)的類符號并且輸入到packageSymbol的members_field屬性中。同時也填充了classSymbol的classfile、flags_field屬性。如有必要,需要調(diào)用enterClass()方法來完成對classSymbol的創(chuàng)建。
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;}?
調(diào)用之前與這后的截圖如下:
在執(zhí)行過某個Symbol的complete()方法后,其中的屬性completer會被置為null。而調(diào)用某個符號Symbol的complete()方法也主要是對members_field進行符號的填充。只有TypeSymbol,也就是PackageSymbol與ClassSymbol有members_field屬性。
?
?
3、調(diào)用memberEnter()方法后處理JCImport語法節(jié)點。查看MemberEnter類的visitImport()方法,最重要的邏輯如下:?
?
// process the non-static imports and the static imports of types. 處理類型的靜態(tài)和非靜態(tài)引入public void visitImport(JCImport jcImport) {JCTree jcTree = jcImport.qualified;Name name = TreeInfo.name(jcTree); // identifier/field/a parameterized typeTypeSymbol typeSymbol;// Create a local environment pointing to this tree to disable// effects of other imports in Resolve.findGlobalTypeEnvironment<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 _TYPprotoKind = _TYP | _PCK;}// 在符號輸入的過程中也可能進行標(biāo)記,如下: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); // 是否是合乎規(guī)范的?importNamed(jcImport.position(), typeSymbol1, environment); // Import given class.}}}如上代碼要處理import java.util.ArrayList;語句。
(1)標(biāo)記java.util,獲取PackageType與typeSymbol,如下截圖。
(2)處理java.util.ArrayList,也就是調(diào)用attributeImportType()方法,返回ClassType類型
(3)調(diào)用importNamed()方法為當(dāng)前環(huán)境的Scope中導(dǎo)入符號。
?
4、對于JCClassDefinition節(jié)點調(diào)用MemberEnter的visitTree()后不做任何處理。但是在MemberEnter的complete(Symbol symbol)方法中對JCClassDefinition語法節(jié)點進行填充。
?
(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關(guān)鍵字來明確繼承一個類,如繼承Thead類時,其superType如下截圖。
(2) 填充classType屬性的interfaces_field和all_interfaces_field屬性
// Determine interfaces.ListBuffer<Type> interfaces = new ListBuffer<Type>();ListBuffer<Type> all_interfaces = null; // lazy initializerSet<Type> interfaceSet = new HashSet<Type>();List<JCExpression> interfaceTrees = jcClassDeclaration.implementing;// 為枚舉類型添加了兩個接口,Comparable和Serializableif ((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.ComparableList.of(classSymbol.type),symbolTable.comparableType.typeSymbol);JCExpression jcExpression = treeMaker.Type(ct);interfaceTrees = interfaceTrees.prepend(jcExpression);// add interface SerializableJCExpression 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 { // 如果進入這個循環(huán),可能已經(jīng)出錯了?if (all_interfaces == null){all_interfaces = new ListBuffer<Type>().appendList(interfaces);}all_interfaces.append(modelMissingTypes(interfaceType, iface, true));}}// 處理annotation注解// java.lang.annotation.Annotationif ( (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) 標(biāo)記類的類型變量
attr.attribTypeVariables(jcClassDeclaration.typeParameters, baseEnvironment);?
(4) 添加默認(rèn)的構(gòu)造函數(shù)
?
// Add default constructorSymbol if needed.// 在非接口且沒有默認(rèn)構(gòu)造函數(shù)的情況下,添加默認(rèn)的構(gòu)造函數(shù)if ((classSymbol.flags() & INTERFACE) == 0 && !TreeInfo.hasConstructors(jcClassDeclaration.defs)) {// 默認(rèn)如下三項都為空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關(guān)鍵字到當(dāng)前的作用域
?
// If this is a class, enter symbols for this and super into current scope.// 如果為一個類,輸入this和super關(guān)鍵字到當(dāng)前的作用域if ((classSymbol.flags_field & INTERFACE) == 0) {// 輸入this符號VarSymbol thisSymbol = new VarSymbol(FINAL | HASINIT, names._this, classSymbol.type, classSymbol);thisSymbol.pos = Position.FIRSTPOS; // firstposenvironment.info.scope.enter(thisSymbol);// 有直接的父類才會輸入super符號???if (classType.supertype_field.typeTag == CLASS) { // 對于接口,supertype_field的typeTag為INTERFACEVarSymbol superSymbol = new VarSymbol(FINAL | HASINIT, names._super, classType.supertype_field, classSymbol);superSymbol.pos = Position.FIRSTPOS;environment.info.scope.enter(superSymbol);}}
?在complete()方法的結(jié)尾處有如下代碼,是通過循環(huán)取出halfcompleted隊列中的值來繼承進行符號填充的。
try {while (halfcompleted.nonEmpty()) {Environment<AttrContext> temp = halfcompleted.next();finish(temp);}} finally {isFirst = true;}
5、處理JCMethodDeclaration
如上的實例中有兩個方法,一個為test方法,另外一個為編譯器默認(rèn)添加的構(gòu)造方法<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 typemethodSymbol.type = signature(jcMethodDeclaration.typeParameters, jcMethodDeclaration.parameters,jcMethodDeclaration.returnType, jcMethodDeclaration.thrown, localEnvironment);} finally {check.setDeferredLintHandler(prevLintHandler);}// Set methodSymbol.parametersListBuffer<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 necessaryif (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默認(rèn)值annotateDefaultValueLater(jcMethodDeclaration.defaultValue, localEnvironment, methodSymbol);}}可以看到主要填充了JCMethodDeclaration的methodSymbol屬性,并且對methodSymbol的flags_field、parameters、type等屬性進行值進行了填充。
?
6、JCVariableDeclaration語法節(jié)點
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/extjs4/p/6627643.html
總結(jié)
以上是生活随笔為你收集整理的关于类的符号输入过程第二篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于STM32F103C6T6HAL库控
- 下一篇: [java学习笔记]-注解和反射