/** * Invoked when current class classified as inner class. Owner of inner classes - is some outer * class, which is either already completed, and thus already has this inner class as member, * either will be completed by {@link org.sonar.java.resolve.BytecodeCompleter}, and thus will * have this inner class as member (see {@link #defineInnerClass(String, int)}). */ private void defineOuterClass(String outerName, String innerName, int flags) { JavaSymbol.TypeJavaSymbol outerClassSymbol = getClassSymbol(outerName, flags); Preconditions.checkState( outerClassSymbol.completer == null || outerClassSymbol.completer instanceof BytecodeCompleter); classSymbol.name = innerName; classSymbol.flags = flags | bytecodeCompleter.filterBytecodeFlags(classSymbol.flags & ~Flags.ACCESS_FLAGS); classSymbol.owner = outerClassSymbol; }
/** Is class accessible in given environment? */ @VisibleForTesting static boolean isAccessible(Env env, JavaSymbol.TypeJavaSymbol c) { final boolean result; switch (c.flags() & Flags.ACCESS_FLAGS) { case Flags.PRIVATE: result = sameOutermostClass(env.enclosingClass, c.owner()); break; case 0: result = env.packge == c.packge(); break; case Flags.PUBLIC: result = true; break; case Flags.PROTECTED: result = env.packge == c.packge() || isInnerSubClass(env.enclosingClass, c.owner()); break; default: throw new IllegalStateException(); } // TODO check accessibility of enclosing type: isAccessible(env, c.type.getEnclosingType()) return result; }
/** * If at this point there is no owner of current class, then this is a top-level class, because * outer classes always will be completed before inner classes - see {@link * #defineOuterClass(String, String, int)}. Owner of top-level classes - is a package. */ @Override public void visitEnd() { if (classSymbol.owner == null) { String flatName = className.replace('/', '.'); classSymbol.name = flatName.substring(flatName.lastIndexOf('.') + 1); classSymbol.owner = bytecodeCompleter.enterPackage(flatName); JavaSymbol.PackageJavaSymbol owner = (JavaSymbol.PackageJavaSymbol) classSymbol.owner; if (owner.members == null) { // package was without classes so far owner.members = new Scope(owner); } owner.members.enter(classSymbol); } }
/** Is given class a subclass of given base class, or an inner class of a subclass? */ private static boolean isInnerSubClass(JavaSymbol.TypeJavaSymbol c, JavaSymbol base) { while (c != null && isSubClass(c, base)) { c = c.owner().enclosingClass(); } return c != null; }